Skip to content

Commit

Permalink
index: move RevWalk tests to inner module
Browse files Browse the repository at this point in the history
The main tests module is getting bigger, and these tests are very specific
to the RevWalk* implementations.
  • Loading branch information
yuja committed Feb 18, 2024
1 parent 924a5fc commit adcb01e
Show file tree
Hide file tree
Showing 2 changed files with 363 additions and 348 deletions.
348 changes: 0 additions & 348 deletions lib/src/default_index/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ pub use self::store::{DefaultIndexStore, DefaultIndexStoreError, DefaultIndexSto

#[cfg(test)]
mod tests {
use std::ops::Range;
use std::sync::Arc;

use itertools::Itertools;
Expand Down Expand Up @@ -62,13 +61,6 @@ mod tests {
move || iter.next().unwrap()
}

fn to_positions_vec(index: CompositeIndex<'_>, commit_ids: &[CommitId]) -> Vec<IndexPosition> {
commit_ids
.iter()
.map(|id| index.commit_id_to_pos(id).unwrap())
.collect()
}

#[test_case(false; "memory")]
#[test_case(true; "file")]
fn index_empty(on_disk: bool) {
Expand Down Expand Up @@ -1135,346 +1127,6 @@ mod tests {
assert_eq!(common_ancestors, vec![id_2]);
}

#[test]
fn test_walk_revs() {
let mut new_change_id = change_id_generator();
let mut index = DefaultMutableIndex::full(3, 16);
// 5
// |\
// 4 | 3
// | |/
// 1 2
// |/
// 0
let id_0 = CommitId::from_hex("000000");
let id_1 = CommitId::from_hex("111111");
let id_2 = CommitId::from_hex("222222");
let id_3 = CommitId::from_hex("333333");
let id_4 = CommitId::from_hex("444444");
let id_5 = CommitId::from_hex("555555");
index.add_commit_data(id_0.clone(), new_change_id(), &[]);
index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
index.add_commit_data(id_2.clone(), new_change_id(), &[id_0.clone()]);
index.add_commit_data(id_3.clone(), new_change_id(), &[id_2.clone()]);
index.add_commit_data(id_4.clone(), new_change_id(), &[id_1.clone()]);
index.add_commit_data(id_5.clone(), new_change_id(), &[id_4.clone(), id_2.clone()]);

let walk_commit_ids = |wanted: &[CommitId], unwanted: &[CommitId]| {
let index = index.as_composite();
let wanted_positions = to_positions_vec(index, wanted);
let unwanted_positions = to_positions_vec(index, unwanted);
index
.walk_revs(&wanted_positions, &unwanted_positions)
.map(|entry| entry.commit_id())
.collect_vec()
};

// No wanted commits
assert!(walk_commit_ids(&[], &[]).is_empty());
// Simple linear walk to roo
assert_eq!(
walk_commit_ids(&[id_4.clone()], &[]),
vec![id_4.clone(), id_1.clone(), id_0.clone()]
);
// Commits that are both wanted and unwanted are not walked
assert_eq!(walk_commit_ids(&[id_0.clone()], &[id_0.clone()]), vec![]);
// Commits that are listed twice are only walked once
assert_eq!(
walk_commit_ids(&[id_0.clone(), id_0.clone()], &[]),
vec![id_0.clone()]
);
// If a commit and its ancestor are both wanted, the ancestor still gets walked
// only once
assert_eq!(
walk_commit_ids(&[id_0.clone(), id_1.clone()], &[]),
vec![id_1.clone(), id_0.clone()]
);
// Ancestors of both wanted and unwanted commits are not walked
assert_eq!(
walk_commit_ids(&[id_2.clone()], &[id_1.clone()]),
vec![id_2.clone()]
);
// Same as above, but the opposite order, to make sure that order in index
// doesn't matter
assert_eq!(
walk_commit_ids(&[id_1.clone()], &[id_2.clone()]),
vec![id_1.clone()]
);
// Two wanted nodes
assert_eq!(
walk_commit_ids(&[id_1.clone(), id_2.clone()], &[]),
vec![id_2.clone(), id_1.clone(), id_0.clone()]
);
// Order of output doesn't depend on order of input
assert_eq!(
walk_commit_ids(&[id_2.clone(), id_1.clone()], &[]),
vec![id_2.clone(), id_1.clone(), id_0]
);
// Two wanted nodes that share an unwanted ancestor
assert_eq!(
walk_commit_ids(&[id_5.clone(), id_3.clone()], &[id_2]),
vec![id_5, id_4, id_3, id_1]
);
}

#[test]
fn test_walk_revs_filter_by_generation() {
let mut new_change_id = change_id_generator();
let mut index = DefaultMutableIndex::full(3, 16);
// 8 6
// | |
// 7 5
// |/|
// 4 |
// | 3
// 2 |
// |/
// 1
// |
// 0
let id_0 = CommitId::from_hex("000000");
let id_1 = CommitId::from_hex("111111");
let id_2 = CommitId::from_hex("222222");
let id_3 = CommitId::from_hex("333333");
let id_4 = CommitId::from_hex("444444");
let id_5 = CommitId::from_hex("555555");
let id_6 = CommitId::from_hex("666666");
let id_7 = CommitId::from_hex("777777");
let id_8 = CommitId::from_hex("888888");
index.add_commit_data(id_0.clone(), new_change_id(), &[]);
index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
index.add_commit_data(id_3.clone(), new_change_id(), &[id_1.clone()]);
index.add_commit_data(id_4.clone(), new_change_id(), &[id_2.clone()]);
index.add_commit_data(id_5.clone(), new_change_id(), &[id_4.clone(), id_3.clone()]);
index.add_commit_data(id_6.clone(), new_change_id(), &[id_5.clone()]);
index.add_commit_data(id_7.clone(), new_change_id(), &[id_4.clone()]);
index.add_commit_data(id_8.clone(), new_change_id(), &[id_7.clone()]);

let walk_commit_ids = |wanted: &[CommitId], unwanted: &[CommitId], range: Range<u32>| {
let index = index.as_composite();
let wanted_positions = to_positions_vec(index, wanted);
let unwanted_positions = to_positions_vec(index, unwanted);
index
.walk_revs(&wanted_positions, &unwanted_positions)
.filter_by_generation(range)
.map(|entry| entry.commit_id())
.collect_vec()
};

// Empty generation bounds
assert_eq!(walk_commit_ids(&[&id_8].map(Clone::clone), &[], 0..0), []);
assert_eq!(
walk_commit_ids(&[&id_8].map(Clone::clone), &[], Range { start: 2, end: 1 }),
[]
);

// Simple generation bounds
assert_eq!(
walk_commit_ids(&[&id_2].map(Clone::clone), &[], 0..3),
[&id_2, &id_1, &id_0].map(Clone::clone)
);

// Ancestors may be walked with different generations
assert_eq!(
walk_commit_ids(&[&id_6].map(Clone::clone), &[], 2..4),
[&id_4, &id_3, &id_2, &id_1].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_5].map(Clone::clone), &[], 2..3),
[&id_2, &id_1].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_5, &id_7].map(Clone::clone), &[], 2..3),
[&id_2, &id_1].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_7, &id_8].map(Clone::clone), &[], 0..2),
[&id_8, &id_7, &id_4].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_6, &id_7].map(Clone::clone), &[], 0..3),
[&id_7, &id_6, &id_5, &id_4, &id_3, &id_2].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_6, &id_7].map(Clone::clone), &[], 2..3),
[&id_4, &id_3, &id_2].map(Clone::clone)
);

// Ancestors of both wanted and unwanted commits are not walked
assert_eq!(
walk_commit_ids(&[&id_5].map(Clone::clone), &[&id_2].map(Clone::clone), 1..5),
[&id_4, &id_3].map(Clone::clone)
);
}

#[test]
#[allow(clippy::redundant_clone)] // allow id_n.clone()
fn test_walk_revs_filter_by_generation_range_merging() {
let mut new_change_id = change_id_generator();
let mut index = DefaultMutableIndex::full(3, 16);
// Long linear history with some short branches
let ids = (0..11)
.map(|n| CommitId::try_from_hex(&format!("{n:06x}")).unwrap())
.collect_vec();
index.add_commit_data(ids[0].clone(), new_change_id(), &[]);
for i in 1..ids.len() {
index.add_commit_data(ids[i].clone(), new_change_id(), &[ids[i - 1].clone()]);
}
let id_branch5_0 = CommitId::from_hex("050000");
let id_branch5_1 = CommitId::from_hex("050001");
index.add_commit_data(id_branch5_0.clone(), new_change_id(), &[ids[5].clone()]);
index.add_commit_data(
id_branch5_1.clone(),
new_change_id(),
&[id_branch5_0.clone()],
);

let walk_commit_ids = |wanted: &[CommitId], range: Range<u32>| {
let index = index.as_composite();
let wanted_positions = to_positions_vec(index, wanted);
index
.walk_revs(&wanted_positions, &[])
.filter_by_generation(range)
.map(|entry| entry.commit_id())
.collect_vec()
};

// Multiple non-overlapping generation ranges to track:
// 9->6: 3..5, 6: 0..2
assert_eq!(
walk_commit_ids(&[&ids[9], &ids[6]].map(Clone::clone), 4..6),
[&ids[5], &ids[4], &ids[2], &ids[1]].map(Clone::clone)
);

// Multiple non-overlapping generation ranges to track, and merged later:
// 10->7: 3..5, 7: 0..2
// 10->6: 4..6, 7->6, 1..3, 6: 0..2
assert_eq!(
walk_commit_ids(&[&ids[10], &ids[7], &ids[6]].map(Clone::clone), 5..7),
[&ids[5], &ids[4], &ids[2], &ids[1], &ids[0]].map(Clone::clone)
);

// Merge range with sub-range (1..4 + 2..3 should be 1..4, not 1..3):
// 8,7,6->5::1..4, B5_1->5::2..3
assert_eq!(
walk_commit_ids(
&[&ids[8], &ids[7], &ids[6], &id_branch5_1].map(Clone::clone),
5..6
),
[&ids[3], &ids[2], &ids[1]].map(Clone::clone)
);
}

#[test]
fn test_walk_revs_descendants_filtered_by_generation() {
let mut new_change_id = change_id_generator();
let mut index = DefaultMutableIndex::full(3, 16);
// 8 6
// | |
// 7 5
// |/|
// 4 |
// | 3
// 2 |
// |/
// 1
// |
// 0
let id_0 = CommitId::from_hex("000000");
let id_1 = CommitId::from_hex("111111");
let id_2 = CommitId::from_hex("222222");
let id_3 = CommitId::from_hex("333333");
let id_4 = CommitId::from_hex("444444");
let id_5 = CommitId::from_hex("555555");
let id_6 = CommitId::from_hex("666666");
let id_7 = CommitId::from_hex("777777");
let id_8 = CommitId::from_hex("888888");
index.add_commit_data(id_0.clone(), new_change_id(), &[]);
index.add_commit_data(id_1.clone(), new_change_id(), &[id_0.clone()]);
index.add_commit_data(id_2.clone(), new_change_id(), &[id_1.clone()]);
index.add_commit_data(id_3.clone(), new_change_id(), &[id_1.clone()]);
index.add_commit_data(id_4.clone(), new_change_id(), &[id_2.clone()]);
index.add_commit_data(id_5.clone(), new_change_id(), &[id_4.clone(), id_3.clone()]);
index.add_commit_data(id_6.clone(), new_change_id(), &[id_5.clone()]);
index.add_commit_data(id_7.clone(), new_change_id(), &[id_4.clone()]);
index.add_commit_data(id_8.clone(), new_change_id(), &[id_7.clone()]);

let visible_heads = [&id_6, &id_8].map(Clone::clone);
let walk_commit_ids = |roots: &[CommitId], heads: &[CommitId], range: Range<u32>| {
let index = index.as_composite();
let root_positions = to_positions_vec(index, roots);
let head_positions = to_positions_vec(index, heads);
index
.walk_revs(&head_positions, &[])
.descendants_filtered_by_generation(&root_positions, range)
.map(|entry| entry.commit_id())
.collect_vec()
};

// Empty generation bounds
assert_eq!(
walk_commit_ids(&[&id_0].map(Clone::clone), &visible_heads, 0..0),
[]
);
assert_eq!(
walk_commit_ids(
&[&id_8].map(Clone::clone),
&visible_heads,
Range { start: 2, end: 1 }
),
[]
);

// Full generation bounds
assert_eq!(
walk_commit_ids(&[&id_0].map(Clone::clone), &visible_heads, 0..u32::MAX),
[&id_0, &id_1, &id_2, &id_3, &id_4, &id_5, &id_6, &id_7, &id_8].map(Clone::clone)
);

// Simple generation bounds
assert_eq!(
walk_commit_ids(&[&id_3].map(Clone::clone), &visible_heads, 0..3),
[&id_3, &id_5, &id_6].map(Clone::clone)
);

// Descendants may be walked with different generations
assert_eq!(
walk_commit_ids(&[&id_0].map(Clone::clone), &visible_heads, 2..4),
[&id_2, &id_3, &id_4, &id_5].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_1].map(Clone::clone), &visible_heads, 2..3),
[&id_4, &id_5].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_2, &id_3].map(Clone::clone), &visible_heads, 2..3),
[&id_5, &id_6, &id_7].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_2, &id_4].map(Clone::clone), &visible_heads, 0..2),
[&id_2, &id_4, &id_5, &id_7].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_2, &id_3].map(Clone::clone), &visible_heads, 0..3),
[&id_2, &id_3, &id_4, &id_5, &id_6, &id_7].map(Clone::clone)
);
assert_eq!(
walk_commit_ids(&[&id_2, &id_3].map(Clone::clone), &visible_heads, 2..3),
[&id_5, &id_6, &id_7].map(Clone::clone)
);

// Roots set contains entries unreachable from heads
assert_eq!(
walk_commit_ids(
&[&id_2, &id_3].map(Clone::clone),
&[&id_8].map(Clone::clone),
0..3
),
[&id_2, &id_4, &id_7].map(Clone::clone)
);
}

#[test]
fn test_heads() {
let mut new_change_id = change_id_generator();
Expand Down
Loading

0 comments on commit adcb01e

Please sign in to comment.