diff --git a/libra/tests/command/fetch_test.rs b/libra/tests/command/fetch_test.rs index 8b1378917..5cb255bef 100644 --- a/libra/tests/command/fetch_test.rs +++ b/libra/tests/command/fetch_test.rs @@ -1 +1,110 @@ +use std::process::Command; +use std::time::Duration; +use tempfile::TempDir; +use tokio::process::Command as TokioCommand; +use tokio::time::timeout; +/// Helper function: Initialize a temporary Libra repository +fn init_temp_repo() -> TempDir { + let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + let temp_path = temp_dir.path(); + + eprintln!("Temporary directory created at: {temp_path:?}"); + assert!(temp_path.is_dir(), "Temporary path is not a valid directory"); + + let output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .arg("init") + .output() + .expect("Failed to execute libra binary"); + + if !output.status.success() { + panic!( + "Failed to initialize libra repository: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + eprintln!("Initialized libra repo at: {temp_path:?}"); + temp_dir +} + +#[tokio::test] +/// Test fetching from an invalid remote repository with timeout +async fn test_fetch_invalid_remote() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + eprintln!("Starting test: fetch from invalid remote"); + + // Configure an invalid remote repository + eprintln!("Adding invalid remote: https://invalid-url.example/repo.git"); + let remote_output = TokioCommand::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["remote", "add", "origin", "https://invalid-url.example/repo.git"]) + .output() + .await + .expect("Failed to add remote"); + + assert!( + remote_output.status.success(), + "Failed to add remote: {}", + String::from_utf8_lossy(&remote_output.stderr) + ); + + // Set upstream branch + eprintln!("Setting upstream to origin/main"); + let branch_output = TokioCommand::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["branch", "--set-upstream-to", "origin/main"]) + .output() + .await + .expect("Failed to set upstream branch"); + + assert!( + branch_output.status.success(), + "Failed to set upstream: {}", + String::from_utf8_lossy(&branch_output.stderr) + ); + + // Attempt to fetch with 15-second timeout to avoid hanging CI + eprintln!("Attempting 'libra fetch' with 15s timeout..."); + let fetch_result = timeout(Duration::from_secs(15), async { + TokioCommand::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .arg("fetch") + .output() + .await + }) + .await; + + match fetch_result { + // Timeout occurred — this is expected for unreachable remotes + Err(_) => { + eprintln!("Fetch timed out after 15 seconds — expected for invalid remote"); + } + // Command completed within timeout + Ok(Ok(output)) => { + + eprintln!("Fetch completed (status: {:?})", output.status); + assert!( + !output.status.success(), + "Fetch should fail when remote is unreachable" + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + !stderr.trim().is_empty(), + "Expected error message in stderr, but was empty" + ); + + eprintln!("Fetch failed as expected: {stderr}"); + } + // Failed to start the command + Ok(Err(e)) => { + + panic!("Failed to run 'libra fetch' command: {e}"); + } + } + + eprintln!("test_fetch_invalid_remote passed"); +} diff --git a/libra/tests/command/lfs_test.rs b/libra/tests/command/lfs_test.rs index 8b1378917..2e61d1bc1 100644 --- a/libra/tests/command/lfs_test.rs +++ b/libra/tests/command/lfs_test.rs @@ -1 +1,107 @@ +use std::process::Command; +use tempfile::TempDir; +/// Helper function: Initialize a temporary Libra repository +fn init_temp_repo() -> TempDir { + let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + let temp_path = temp_dir.path(); + + // Variables can be used directly in the `format!` string + // FIX: Removed {:?} and added variable directly with formatting + println!("Temporary directory created at: {temp_path:?}"); + assert!(temp_path.is_dir(), "Temporary path is not a valid directory"); + + // Using env!("CARGO_BIN_EXE_libra") to get the path to the libra executable + let output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .arg("init") + .output() + .expect("Failed to execute libra binary"); + + if !output.status.success() { + panic!( + "Failed to initialize libra repository: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + temp_dir +} + +#[tokio::test] +/// Test track/untrack path rule management +async fn test_lfs_track_untrack() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + // Add a path rule + // FIX: Removed & from args + let track_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["lfs", "track", "*.txt"]) // Changed &[...] to [...] + .output() + .expect("Failed to track path"); + assert!( + track_output.status.success(), + "Failed to track path: {}", + String::from_utf8_lossy(&track_output.stderr) + ); + + // Remove a path rule + // FIX: Removed & from args + let untrack_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["lfs", "untrack", "*.txt"]) // Changed &[...] to [...] + .output() + .expect("Failed to untrack path"); + assert!( + untrack_output.status.success(), + "Failed to untrack path: {}", + String::from_utf8_lossy(&untrack_output.stderr) + ); +} + +#[tokio::test] +/// Test file status viewing +async fn test_lfs_ls_files() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + // Create a test file and add it to LFS + let file_path = temp_path.join("tracked_file.txt"); + std::fs::write(&file_path, "Tracked content").expect("Failed to create tracked file"); + + // FIX: Removed & from args + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["lfs", "track", "*.txt"]) // Changed &[...] to [...] + .output() + .expect("Failed to track file"); + + // FIX: Removed & from args + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["add", "tracked_file.txt"]) // Changed &[...] to [...] + .output() + .expect("Failed to add file to LFS"); + + // View file status + // FIX: Removed & from args + let ls_files_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["lfs", "ls-files"]) // Changed &[...] to [...] + .output() + .expect("Failed to list LFS files"); + assert!( + ls_files_output.status.success(), + "Failed to list LFS files: {}", + String::from_utf8_lossy(&ls_files_output.stderr) + ); + + let stdout = String::from_utf8_lossy(&ls_files_output.stdout); + // FIX: Variables can be used directly in the `format!` string + assert!( + stdout.contains("tracked_file.txt"), + "LFS file list does not contain expected file: {stdout}", // Changed {} to direct variable embed + ); +} diff --git a/libra/tests/command/merge_test.rs b/libra/tests/command/merge_test.rs index 8b1378917..22564decb 100644 --- a/libra/tests/command/merge_test.rs +++ b/libra/tests/command/merge_test.rs @@ -1 +1,187 @@ +use std::process::Command; +use tempfile::TempDir; + +/// Helper function: Initialize a temporary Libra repository +fn init_temp_repo() -> TempDir { + let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + let temp_path = temp_dir.path(); + + println!("Temporary directory created at: {temp_path:?}"); + assert!(temp_path.is_dir(), "Temporary path is not a valid directory"); + + let output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .arg("init") + .output() + .expect("Failed to execute libra binary"); + + if !output.status.success() { + panic!( + "Failed to initialize libra repository: {}", + String::from_utf8_lossy(&output.stderr) + ); + } + + temp_dir +} + +#[tokio::test] +/// Test fast-forward merge of local branches +async fn test_merge_fast_forward() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + // Create and switch to the feature branch + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["branch", "feature"]) + .output() + .expect("Failed to create branch"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["checkout", "feature"]) + .output() + .expect("Failed to checkout branch"); + + // Commit changes on the feature branch + let file_path = temp_path.join("file.txt"); + std::fs::write(&file_path, "Feature content").expect("Failed to write file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["add", "."]) + .output() + .expect("Failed to add file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["commit", "-m", "Add feature content"]) + .output() + .expect("Failed to commit"); + + // Switch back to the main branch and perform fast-forward merge + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["checkout", "main"]) + .output() + .expect("Failed to checkout main branch"); + + let merge_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["merge", "feature"]) + .output() + .expect("Failed to merge branch"); + assert!( + merge_output.status.success(), + "Fast-forward merge failed: {}", + String::from_utf8_lossy(&merge_output.stderr) + ); +} + + +#[tokio::test] +/// Test merging a remote branch +async fn test_merge_remote_branch() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + // Simulate adding a remote branch + // FIX: Remove & + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["remote", "add", "origin", "https://example.com/repo.git"]) + .output() + .expect("Failed to add remote"); + + // Merge the remote branch + + let merge_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["merge", "origin/feature"]) + .output() + .expect("Failed to merge remote branch"); + assert!( + merge_output.status.success(), + "Merge remote branch failed: {}", + String::from_utf8_lossy(&merge_output.stderr) + ); +} + + +#[tokio::test] +/// Test merging branches with no common ancestor +async fn test_merge_no_common_ancestor() { + let temp_repo = init_temp_repo(); + let temp_path = temp_repo.path(); + + // Create and switch to branch1 + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["branch", "branch1"]) + .output() + .expect("Failed to create branch"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["checkout", "branch1"]) + .output() + .expect("Failed to checkout branch"); + + // Commit changes on branch1 + let branch1_file = temp_path.join("branch1.txt"); + std::fs::write(&branch1_file, "Branch1 content").expect("Failed to write file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["add", "."]) + .output() + .expect("Failed to add file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["commit", "-m", "Add branch1 content"]) + .output() + .expect("Failed to commit"); + + // Create and switch to branch2 + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["checkout", "-b", "branch2", "HEAD~1"]) + .output() + .expect("Failed to create branch"); + + // Commit changes on branch2 + let branch2_file = temp_path.join("branch2.txt"); + std::fs::write(&branch2_file, "Branch2 content").expect("Failed to write file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["add", "."]) + .output() + .expect("Failed to add file"); + + Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["commit", "-m", "Add branch2 content"]) + .output() + .expect("Failed to commit"); + + // Attempt to merge branches with no common ancestor + + let merge_output = Command::new(env!("CARGO_BIN_EXE_libra")) + .current_dir(temp_path) + .args(["merge", "branch2"]) + .output() + .expect("Failed to merge branch"); + assert!( + merge_output.status.success(), + "Merge no common ancestor branch failed: {}", + String::from_utf8_lossy(&merge_output.stderr) + ); +}