Files
gitks/tests/branch_test.rs
T
zhenyi dcb0fb74c5 feat(core): implement Git repository operations with gRPC services
- Add advertise_refs functionality for Git protocol communication
- Implement archive service with TAR/ZIP format support and streaming
- Create blame service for Git file annotation with line tracking
- Add branch management including create, delete, rename and compare operations
- Implement merge checking with conflict detection and fast-forward handling
- Add cherry-pick functionality for applying commits between branches
- Integrate gix library for Git repository operations and object handling
- Add comprehensive test suite covering all Git operations
- Implement proper error handling and repository validation
- Add pagination support for large result sets
- Create protobuf definitions for all Git operations and data structures
- Add build system for gRPC code generation and dependency management
2026-06-04 13:05:38 +08:00

201 lines
5.7 KiB
Rust

mod common;
use gitks::pb::*;
#[test]
fn test_list_branches() {
let (_dir, gb) = common::setup_bare_repo();
let result = gb
.list_branches(ListBranchesRequest {
repository: None,
pattern: String::new(),
merged_into_head: false,
not_merged_into_head: false,
pagination: None,
sort_direction: 0,
})
.expect("list_branches");
let names: Vec<String> = result.branches.iter().map(|b| b.name.clone()).collect();
assert!(names.contains(&"feature".to_string()));
assert!(names.contains(&"main".to_string()));
assert!(result.branches.len() >= 2);
}
#[test]
fn test_list_branches_merged_filter() {
let (_dir, gb) = common::setup_bare_repo();
let merged = gb
.list_branches(ListBranchesRequest {
repository: None,
pattern: String::new(),
merged_into_head: true,
not_merged_into_head: false,
pagination: None,
sort_direction: 0,
})
.expect("list_branches merged");
let not_merged = gb
.list_branches(ListBranchesRequest {
repository: None,
pattern: String::new(),
merged_into_head: false,
not_merged_into_head: true,
pagination: None,
sort_direction: 0,
})
.expect("list_branches not merged");
let merged_names: Vec<&str> = merged.branches.iter().map(|b| b.name.as_str()).collect();
let not_merged_names: Vec<&str> = not_merged
.branches
.iter()
.map(|b| b.name.as_str())
.collect();
assert!(
merged_names.contains(&"main"),
"main should be merged into HEAD, got: {:?}",
merged_names
);
assert!(
not_merged_names.contains(&"feature"),
"feature should NOT be merged into HEAD, got: {:?}",
not_merged_names
);
}
#[test]
fn test_get_branch() {
let (_dir, gb) = common::setup_bare_repo();
let branch = gb
.get_branch(GetBranchRequest {
repository: None,
name: "feature".into(),
})
.expect("get_branch");
assert_eq!(branch.full_ref, "refs/heads/feature");
let oid = branch.target_oid.unwrap();
assert!(!oid.value.is_empty());
assert_eq!(oid.value.len(), 20);
assert_eq!(oid.hex.len(), 40);
}
#[test]
fn test_branch_pagination() {
let (_dir, gb) = common::setup_bare_repo();
let result = gb
.list_branches(ListBranchesRequest {
repository: None,
pattern: String::new(),
merged_into_head: false,
not_merged_into_head: false,
pagination: Some(Pagination {
page_size: 1,
page_token: String::new(),
}),
sort_direction: 0,
})
.expect("list_branches page 1");
let page_info = result.page_info.unwrap();
assert_eq!(result.branches.len(), 1);
assert!(page_info.has_next_page);
let result2 = gb
.list_branches(ListBranchesRequest {
repository: None,
pattern: String::new(),
merged_into_head: false,
not_merged_into_head: false,
pagination: Some(Pagination {
page_size: 1,
page_token: page_info.next_page_token,
}),
sort_direction: 0,
})
.expect("list_branches page 2");
assert!(!result2.branches.is_empty());
assert_ne!(result.branches[0].name, result2.branches[0].name);
}
#[test]
fn test_create_and_delete_branch() {
let (_dir, gb) = common::setup_bare_repo();
let branch = gb
.create_branch(CreateBranchRequest {
repository: None,
name: "new-branch".into(),
start_point: Some(ObjectSelector {
selector: Some(object_selector::Selector::Revision(ObjectName {
revision: "main".into(),
})),
}),
force: false,
})
.expect("create_branch");
assert_eq!(branch.name, "new-branch");
gb.delete_branch(DeleteBranchRequest {
repository: None,
name: "new-branch".into(),
force: true,
})
.expect("delete_branch");
let result = gb.get_branch(GetBranchRequest {
repository: None,
name: "new-branch".into(),
});
assert!(result.is_err(), "deleted branch should not exist");
}
#[test]
fn test_rename_branch() {
let (_dir, gb) = common::setup_bare_repo();
gb.create_branch(CreateBranchRequest {
repository: None,
name: "to-rename".into(),
start_point: Some(ObjectSelector {
selector: Some(object_selector::Selector::Revision(ObjectName {
revision: "main".into(),
})),
}),
force: false,
})
.expect("create branch for rename");
let renamed = gb
.rename_branch(RenameBranchRequest {
repository: None,
old_name: "to-rename".into(),
new_name: "renamed".into(),
})
.expect("rename_branch");
assert_eq!(renamed.name, "renamed");
let old = gb.get_branch(GetBranchRequest {
repository: None,
name: "to-rename".into(),
});
assert!(old.is_err(), "old branch name should not exist");
}
#[test]
fn test_compare_branch() {
let (_dir, gb) = common::setup_bare_repo();
let result = gb
.compare_branch(CompareBranchRequest {
repository: None,
source_branch: "feature".into(),
target_branch: "main".into(),
})
.expect("compare_branch");
assert!(
result.ahead_by > 0 || result.behind_by > 0,
"branches should differ"
);
assert!(result.merge_base.is_some(), "should find merge base");
}