radicle: fix stream tests

The stream tests did not take into account that the tips of previous COB entries
need to be inserted so that a Git history can be formed.

This was surfaced by the added regression test.
This commit is contained in:
Fintan Halpenny 2025-08-20 08:03:31 +01:00
parent 0c6ff06c65
commit a670b6e668
1 changed files with 95 additions and 23 deletions

View File

@ -190,20 +190,37 @@ mod tests {
let n = gen::<u8>(1).clamp(1, 10); let n = gen::<u8>(1).clamp(1, 10);
let mut entries = Vec::with_capacity(n.into()); let mut entries = Vec::with_capacity(n.into());
let mut parent = None;
for _ in 0..n { for _ in 0..n {
// Number of actions in this bop // Number of actions in this op
let m = gen::<u8>(1).clamp(1, 3); let m = gen::<u8>(1).clamp(1, 3);
let contents = NonEmpty::collect((0..m).map(|_| { let contents = create_contents((0..m).map(|_| arbitrary::alphanumeric(1)));
let entry = create_entry(repo, signer, contents, parent);
parent = Some(entry.id);
entries.push(entry);
}
entries
}
fn create_contents(values: impl Iterator<Item = String>) -> NonEmpty<Vec<u8>> {
NonEmpty::collect(values.map(|value| {
json::to_vec(&json!({ json::to_vec(&json!({
"test": arbitrary::alphanumeric(1), "test": value,
})) }))
.unwrap() .unwrap()
})) }))
.unwrap(); .unwrap()
let entry = repo }
.store(
fn create_entry(
repo: &git2::Repository,
signer: &MockSigner,
contents: NonEmpty<Vec<u8>>,
parent: Option<Oid>,
) -> cob::Entry {
repo.store(
None, None,
vec![], parent.into_iter().collect(),
signer, signer,
cob::change::Template { cob::change::Template {
type_name: typename(), type_name: typename(),
@ -213,10 +230,7 @@ mod tests {
contents, contents,
}, },
) )
.unwrap(); .unwrap()
entries.push(entry);
}
entries
} }
/// all === from(root) /// all === from(root)
@ -309,7 +323,7 @@ mod tests {
.cloned() .cloned()
.collect::<BTreeSet<_>>(), .collect::<BTreeSet<_>>(),
from_until_s, from_until_s,
"from: {from_s:?}\nuntil: {until_s:?}" "\nfrom_until: {from_until_s:?}\nfrom: {from_s:?}\nuntil: {until_s:?}"
) )
} }
@ -379,4 +393,62 @@ mod tests {
let stream = Stream::<json::Value>::new(&repo, history, typename()); let stream = Stream::<json::Value>::new(&repo, history, typename());
prop_from_until(&stream, from, until) prop_from_until(&stream, from, until)
} }
#[test]
fn test_regression_from_until() {
let tmp = tempfile::tempdir().unwrap();
let (repo, _) = test::fixtures::repository(tmp.path());
let signer = MockSigner::default();
// Set up 3 entries that make up the COB history
let op1 = create_entry(
&repo,
&signer,
create_contents(std::iter::once("hello".to_string())),
None,
);
let op2 = create_entry(
&repo,
&signer,
create_contents(std::iter::once("radicle".to_string())),
Some(op1.id),
);
let op3 = create_entry(
&repo,
&signer,
create_contents(std::iter::once("world".to_string())),
Some(op2.id),
);
// The history spans from the 1st op to the last
let history = CobRange {
root: op1.id,
until: op3.id.into(),
};
let stream = Stream::<json::Value>::new(&repo, history, typename());
eprintln!("Op 1: {}", op1.id);
eprintln!("Op 2: {}", op2.id);
eprintln!("Op 3: {}", op3.id);
// "since" the root operation should include all operations
assert_eq!(
stream
.since(op1.id)
.unwrap()
.map(|op| op.unwrap().id)
.collect::<BTreeSet<_>>(),
[op1.id, op2.id, op3.id]
.into_iter()
.collect::<BTreeSet<_>>()
);
// "until" the second operation should only include up to the second operation
assert_eq!(
stream
.until(op2.id)
.unwrap()
.map(|op| op.unwrap().id)
.collect::<BTreeSet<_>>(),
[op1.id, op2.id].into_iter().collect::<BTreeSet<_>>()
);
prop_from_until(&stream, op1.id, op2.id);
}
} }