You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
3.9 KiB
Rust

//! Tests for the `Vec`-like API.
//!
//! The main purpose of these tests is not to cover all corner cases, but
//! rather to show that they behave like there counterparts on `Vec`.
use chronofold::{Change, Chronofold, LogIndex, Session};
#[test]
fn is_empty() {
let vec = Vec::<char>::default();
let mut cfold = Chronofold::<u8, char>::default();
let idx = cfold.session(1).push_back('!');
cfold.session(1).remove(idx);
assert_eq!(vec.is_empty(), cfold.is_empty());
}
#[test]
fn len() {
let mut vec = Vec::<char>::default();
vec.extend("len".chars());
let mut cfold = Chronofold::<u8, char>::default();
cfold.session(1).extend("len".chars());
let idx = cfold.session(1).push_back('?');
cfold.session(1).remove(idx);
assert_eq!(vec.len(), cfold.len());
}
#[test]
fn get() {
let mut vec = Vec::<char>::default();
vec.extend("abc".chars());
let mut cfold = Chronofold::<u8, char>::default();
cfold.session(1).extend("abc".chars());
assert_eq!(Some(&'b'), vec.get(1));
assert_eq!(Some(&Change::Insert('b')), cfold.get(LogIndex(2)));
}
#[test]
fn clear() {
assert_elements_eq(
"foobar".chars(),
|vec| {
vec.clear();
},
|cfold_session| {
cfold_session.clear();
},
);
}
#[test]
fn insert_after() {
assert_elements_eq(
"fobar".chars(),
|vec| {
vec.insert(2, 'o');
},
|cfold_session| {
cfold_session.insert_after(LogIndex(2), 'o');
},
);
}
#[test]
fn extend() {
// Extend empty sequence:
assert_elements_eq(
"".chars(),
|vec| {
vec.extend("foo".chars());
},
|cfold_session| {
cfold_session.extend("foo".chars());
},
);
// Extend non-empty sequence:
assert_elements_eq(
"foo".chars(),
|vec| {
vec.extend("bar".chars());
},
|cfold_session| {
cfold_session.extend("bar".chars());
},
);
}
#[test]
fn splice() {
// Replace the whole sequence by using an unbounded range:
assert_elements_eq(
"bar".chars(),
|vec| {
vec.splice(.., "foo".chars());
},
|cfold_session| {
cfold_session.splice(.., "foo".chars());
},
);
// Insert a new sequence without removing anything:
assert_elements_eq(
"foo!".chars(),
|vec| {
vec.splice(3..3, "bar".chars());
},
|cfold_session| {
cfold_session.splice(LogIndex(4)..LogIndex(4), "bar".chars());
},
);
// Insert a new sequence in an empty vector/chronofold:
assert_elements_eq(
"".chars(),
|vec| {
vec.splice(0..0, "foo".chars());
},
|cfold_session| {
cfold_session.splice(LogIndex(0)..LogIndex(0), "foo".chars());
},
);
// Extend a sequence by using an out-of-bound index. There's a subtle
// difference here: `Vec.splice` only allows indices <= `Vec.len()`, the
// chronofold extends for all out-of-bound indices.
assert_elements_eq(
"foo".chars(),
|vec| {
vec.splice(3..3, "bar".chars());
},
|cfold_session| {
cfold_session.splice(LogIndex(4)..LogIndex(4), "bar".chars());
},
);
}
fn assert_elements_eq<I, T, F, G>(initial_values: I, mutate_vec: F, mutate_chronofold: G)
where
I: Iterator<Item = T>,
F: FnOnce(&mut Vec<T>),
G: FnOnce(&mut Session<u8, T>),
T: PartialEq + Clone + std::fmt::Debug,
{
let mut vec: Vec<T> = initial_values.collect();
let mut cfold = Chronofold::<u8, T>::default();
let mut cfold_session = cfold.session(1);
cfold_session.extend(vec.clone().into_iter());
mutate_vec(&mut vec);
mutate_chronofold(&mut cfold_session);
assert_eq!(
vec.iter().collect::<Vec<_>>(),
cfold.iter_elements().collect::<Vec<_>>()
);
}