Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6cd9fe4
feat:增加add、diff、remove命令测试用例
Ming0213 Jul 30, 2025
0cb5ab6
Merge branch 'main' into feat-ming0213
Ming0213 Jul 30, 2025
8c5bf11
Update libra/tests/command/remove_test.rs
Ming0213 Jul 30, 2025
9b95536
Update libra/tests/command/add_test.rs
Ming0213 Jul 30, 2025
976bb4d
Update libra/tests/command/add_test.rs
Ming0213 Jul 30, 2025
b1b71ad
Update libra/tests/command/diff_test.rs
Ming0213 Jul 30, 2025
9db7856
bugFix:修复add_test.rs、diff_test.rs、remove_test.rs三个测试用例的Clippy检查的报错
Ming0213 Jul 30, 2025
654704b
libra:为add、diff、remove命令添加测试用例
Ming0213 Jul 31, 2025
13d839f
Update libra/tests/command/add_test.rs
Ming0213 Jul 31, 2025
66fb59b
Update libra/tests/command/add_test.rs
Ming0213 Jul 31, 2025
c65258c
Update libra/tests/command/add_test.rs
Ming0213 Jul 31, 2025
2f907a1
Merge branch 'main' into feature/ming0213
Ming0213 Jul 31, 2025
5dec50f
Merge branch 'main' into feature/ming0213
genedna Jul 31, 2025
6ce6fcd
Merge branch 'main' into feature/ming0213
genedna Jul 31, 2025
1b312cf
bugFix:修复add_test、remove_test、diff_test三个文件的相应ClipyCheck错误
Ming0213 Jul 31, 2025
700aa4c
merge add_test.rs
Ming0213 Jul 31, 2025
3753014
bugFix:修复ClipyCheck错误
Ming0213 Jul 31, 2025
212eca5
Merge branch 'main' into feature/ming0213
genedna Jul 31, 2025
b7d90b6
Merge branch 'main' into feature/ming0213
genedna Jul 31, 2025
a501bd6
bugFix:继续修复ClipyCheck错误
Ming0213 Aug 1, 2025
e53c438
Merge branch 'feature/ming0213' of github.com:Ming0213/mega into feat…
Ming0213 Aug 1, 2025
cdf3bc8
bugFix:继续修复ClipyCheck错误
Ming0213 Aug 1, 2025
c23bbfd
bugFix:继续修复ClipyCheck错误
Ming0213 Aug 1, 2025
10a4533
bugFix:继续修复ClipuCheck错误
Ming0213 Aug 1, 2025
9c742e5
Merge branch 'main' into feature/ming0213
genedna Aug 1, 2025
9a5ff56
Merge branch 'main' into feature/ming0213
genedna Aug 1, 2025
607534e
bugFix:继续修复ClippyCheck错误
Ming0213 Aug 4, 2025
f670c40
合并
Ming0213 Aug 4, 2025
4290c58
Merge branch 'main' into feature/ming0213
Ming0213 Aug 4, 2025
3227ad9
bugFix:修复报错
Ming0213 Aug 4, 2025
b30ae6d
Merge branch 'main' into feature/ming0213
Ming0213 Aug 4, 2025
3db0906
Merge branch 'main' into feature/ming0213
Ming0213 Aug 4, 2025
ae7c0f2
Merge branch 'main' into feature/ming0213
Ming0213 Aug 4, 2025
b28904c
Update libra/tests/command/remove_test.rs
Ming0213 Aug 4, 2025
70e2ac3
Update libra/tests/command/remove_test.rs
Ming0213 Aug 4, 2025
0554415
bugFix:修复错误
Ming0213 Aug 4, 2025
c0d3baf
bugFix:修复错误
Ming0213 Aug 4, 2025
5074877
bugFix:修复错误
Ming0213 Aug 4, 2025
1130c6a
Merge branch 'main' into feature/ming0213
genedna Aug 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Cargo.lock
.DS_Store
**/*.dylib

.cursor
.md

# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.VSCodeCounter

Expand Down
26 changes: 13 additions & 13 deletions libra/src/command/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,15 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> {
let mut index = Index::load(&idx_file)?;

// check if pathspec is all in index (skip if force is enabled)
if !args.force && !validate_pathspec(&args.pathspec, &index) {
return Ok(());
if !args.force {
validate_pathspec(&args.pathspec, &index)?
}

let dirs = get_dirs(&args.pathspec, &index, args.force);
if !dirs.is_empty() && !args.recursive {
println!(
"fatal: not removing '{}' recursively without -r",
dirs[0].bright_blue()
); // Git print first
return Ok(());
let error_msg = format!("not removing '{}' recursively without -r", dirs[0]);
println!("fatal: {error_msg}");
return Err(GitError::CustomError(error_msg));
}

for path_str in args.pathspec.iter() {
Expand Down Expand Up @@ -87,10 +85,11 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> {

/// check if pathspec is all valid(in index)
/// - if path is a dir, check if any file in the dir is in index
fn validate_pathspec(pathspec: &[String], index: &Index) -> bool {
fn validate_pathspec(pathspec: &[String], index: &Index) -> Result<(), GitError> {
if pathspec.is_empty() {
println!("fatal: No pathspec was given. Which files should I remove?");
return false;
let error_msg = "No pathspec was given. Which files should I remove?".to_string();
println!("fatal: {error_msg}");
return Err(GitError::CustomError(error_msg));
}
for path_str in pathspec.iter() {
let path = PathBuf::from(path_str);
Expand All @@ -99,12 +98,13 @@ fn validate_pathspec(pathspec: &[String], index: &Index) -> bool {
// not tracked, but path may be a directory
// check if any tracked file in the directory
if !index.contains_dir_file(&path_wd) {
println!("fatal: pathspec '{path_str}' did not match any files");
return false;
let error_msg = format!("pathspec '{path_str}' did not match any files");
println!("fatal: {error_msg}");
return Err(GitError::CustomError(error_msg));
}
}
}
true
Ok(())
}

/// run after `validate_pathspec`
Expand Down
253 changes: 253 additions & 0 deletions libra/tests/command/add_test.rs
Original file line number Diff line number Diff line change
@@ -1 +1,254 @@
use super::*;
use std::fs;
use std::io::Write;

#[tokio::test]
#[serial]
/// Tests the basic functionality of add command by adding a single file
async fn test_add_single_file() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create a new file
let file_content = "Hello, World!";
let file_path = "test_file.txt";
let mut file = fs::File::create(file_path).unwrap();
file.write_all(file_content.as_bytes()).unwrap();

// Execute add command
add::execute(AddArgs {
pathspec: vec![String::from(file_path)],
all: false,
update: false,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Verify the file was added to index.
let changes = changes_to_be_committed().await;

assert!(changes.new.iter().any(|x| x.to_str().unwrap() == file_path));
}

#[tokio::test]
#[serial]
/// Tests adding multiple files at once
async fn test_add_multiple_files() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create multiple files
for i in 1..=3 {
let file_content = format!("File content {i}");
let file_path = format!("test_file_{i}.txt");
let mut file = fs::File::create(&file_path).unwrap();
file.write_all(file_content.as_bytes()).unwrap();
}

// Execute add command
add::execute(AddArgs {
pathspec: vec![
String::from("test_file_1.txt"),
String::from("test_file_2.txt"),
String::from("test_file_3.txt"),
],
all: false,
update: false,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Verify all files were added to index
let changes = changes_to_be_committed().await;
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_1.txt"));
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_2.txt"));
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_3.txt"));
}

#[tokio::test]
#[serial]
/// Tests the --all flag which adds all files in the working tree
async fn test_add_all_flag() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create multiple files
for i in 1..=3 {
let file_content = format!("File content {i}");
let file_path = format!("test_file_{i}.txt");
let mut file = fs::File::create(&file_path).unwrap();
file.write_all(file_content.as_bytes()).unwrap();
}

// Execute add command with --all flag
add::execute(AddArgs {
pathspec: vec![],
all: true,
update: false,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Verify all files were added to index
let changes = changes_to_be_committed().await;
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_1.txt"));
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_2.txt"));
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == "test_file_3.txt"));
}

#[tokio::test]
#[serial]
/// Tests the --update flag which only updates files already in the index
async fn test_add_update_flag() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create files and add one to the index
let tracked_file = "tracked_file.txt";
let untracked_file = "untracked_file.txt";

// Create and write initial content
let mut file1 = fs::File::create(tracked_file).unwrap();
file1.write_all(b"Initial content").unwrap();

let mut file2 = fs::File::create(untracked_file).unwrap();
file2.write_all(b"Initial content").unwrap();

// Add only one file to the index
add::execute(AddArgs {
pathspec: vec![String::from(tracked_file)],
all: false,
update: false,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Modify both files
let mut file1 = fs::OpenOptions::new().write(true).truncate(true).open(tracked_file).unwrap();
file1.write_all(b" - Modified").unwrap();

let mut file2 = fs::OpenOptions::new().write(true).truncate(true).open(untracked_file).unwrap();
file2.write_all(b" - Modified").unwrap();

// Execute add command with --update flag
add::execute(AddArgs {
pathspec: vec![String::from(".")],
all: false,
update: true,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Verify only tracked file was updated
let changes = changes_to_be_staged();
// Tracked file should not appear in changes (because it was updated in index)
assert!(!changes.modified.iter().any(|x| x.to_str().unwrap() == tracked_file));
// Untracked file should still be untracked and show as new
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == untracked_file));
}

#[tokio::test]
#[serial]
/// Tests adding files with respect to ignore patterns in .libraignore
async fn test_add_with_ignore_patterns() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create .libraignore file
let mut ignore_file = fs::File::create(".libraignore").unwrap();
ignore_file.write_all(b"ignored_*.txt\nignore_dir/**").unwrap();

// Create files that should be ignored and not ignored
let ignored_file = "ignored_file.txt";
let tracked_file = "tracked_file.txt";

// Create directory that should be ignored
fs::create_dir("ignore_dir").unwrap();
let ignored_dir_file = "ignore_dir/file.txt";

// Create and write content
let mut file1 = fs::File::create(ignored_file).unwrap();
file1.write_all(b"Should be ignored").unwrap();

let mut file2 = fs::File::create(tracked_file).unwrap();
file2.write_all(b"Should be tracked").unwrap();

let mut file3 = fs::File::create(ignored_dir_file).unwrap();
file3.write_all(b"Should be ignored").unwrap();

// Execute add command with all files
add::execute(AddArgs {
pathspec: vec![String::from(".")],
all: true,
update: false,
refresh: false,
verbose: false,
dry_run: false,
ignore_errors: false,
})
.await;

// Verify only non-ignored files were added
let changes_staged = changes_to_be_staged();
let changes_committed = changes_to_be_committed().await;

// Ignored files should not appear in any status (they are ignored)
assert!(!changes_staged.new.iter().any(|x| x.to_str().unwrap() == ignored_file));
assert!(!changes_staged.new.iter().any(|x| x.to_str().unwrap() == ignored_dir_file));
assert!(!changes_committed.new.iter().any(|x| x.to_str().unwrap() == ignored_file));
assert!(!changes_committed.new.iter().any(|x| x.to_str().unwrap() == ignored_dir_file));

// Non-ignored file should not show as new in staged (was added) but should show in committed
assert!(!changes_staged.new.iter().any(|x| x.to_str().unwrap() == tracked_file));
assert!(changes_committed.new.iter().any(|x| x.to_str().unwrap() == tracked_file));
}

#[tokio::test]
#[serial]
/// Tests the dry-run flag which should not actually add files
async fn test_add_dry_run() {
let test_dir = tempdir().unwrap();
test::setup_with_new_libra_in(test_dir.path()).await;
let _guard = test::ChangeDirGuard::new(test_dir.path());

// Create a file.
let file_path = "test_file.txt";
let mut file = fs::File::create(file_path).unwrap();
file.write_all(b"Test content").unwrap();

// Execute add command with dry-run
add::execute(AddArgs {
pathspec: vec![String::from(file_path)],
all: false,
update: false,
refresh: false,
verbose: false,
dry_run: true,
ignore_errors: false,
})
.await;

// Verify the file was not actually added to index
let changes = changes_to_be_staged();
assert!(changes.new.iter().any(|x| x.to_str().unwrap() == file_path));
}
Loading
Loading