use super::*;
use crate::working_copy::WorkingCopy;
#[test]
fn same_file_test() -> Result<(), anyhow::Error> {
same_file_("file", "alice", "bob")
}
#[test]
fn same_file_dirs_test() -> Result<(), anyhow::Error> {
same_file_("file", "alice/file", "bob/file")
}
fn same_file_(file: &str, alice: &str, bob: &str) -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file(file, contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
txn_alice.add_file(file).unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_alice.rename(file, alice)?;
txn_alice.move_file(file, alice)?;
debug!("repo_bob = {:?}", repo_alice.list_files());
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.rename(file, bob)?;
txn_bob.move_file(file, bob)?;
debug!("repo_bob = {:?}", repo_bob.list_files());
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
match conflicts[0] {
Conflict::MultipleNames { .. } => {}
ref c => panic!("{:#?}", c),
}
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
alice,
true,
)?;
if !conflicts.is_empty() {
panic!("conflicts = {:#?}", conflicts);
}
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
bob,
true,
)?;
if !conflicts.is_empty() {
panic!("conflicts = {:#?}", conflicts);
}
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
match conflicts[0] {
Conflict::MultipleNames { .. } => {}
ref c => panic!("{:#?}", c),
}
let bob_solution =
record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("conflicts = {:#?}", conflicts);
}
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_solution)?;
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("conflicts = {:#?}", conflicts);
}
debug!("repo_alice = {:?}", repo_alice.list_files());
debug!("repo_bob = {:?}", repo_bob.list_files());
debug_tree(&txn_bob, "debug_tree")?;
Ok(())
}
#[test]
fn same_name_test() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file("file1", contents.to_vec());
repo_alice.add_file("file2", contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice")?;
txn_alice.add_file("file1")?;
txn_alice.add_file("file2")?;
info!("recording file additions");
debug!("working_copy = {:?}", repo_alice);
debug_tree(&txn_alice, "debug_tree")?;
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_alice.rename("file1", "file")?;
txn_alice.move_file("file1", "file")?;
debug!("repo_bob = {:?}", repo_alice.list_files());
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.rename("file2", "file")?;
txn_bob.move_file("file2", "file")?;
debug!("repo_bob = {:?}", repo_bob.list_files());
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
assert!(!conflicts.is_empty());
let mut files_alice = repo_alice.list_files();
debug!("repo_alice = {:?}", files_alice);
assert_eq!(files_alice.len(), 2);
files_alice.sort();
assert_eq!(files_alice[0], "file");
assert!(files_alice[1].starts_with("file."));
txn_alice.move_file(&files_alice[1], "a1")?;
repo_alice.rename(&files_alice[0], "file")?;
repo_alice.rename(&files_alice[1], "a1")?;
let solution_alice = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
let mut files_bob = repo_bob.list_files();
debug!("repo_bob = {:?}", files_bob);
assert_eq!(files_bob.len(), 2);
files_bob.sort();
assert_eq!(files_bob[0], "file");
assert!(files_bob[1].starts_with("file."));
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, solution_alice)?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("conflicts = {:#?}", conflicts);
}
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
let mut files_bob = repo_bob.list_files();
files_bob.sort();
assert_eq!(files_bob, vec!["a1", "file"]);
Ok(())
}
#[test]
fn file_conflicts_same_name_and_two_names() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let mut repo_charlie = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file("file1", contents.to_vec());
repo_alice.add_file("file2", contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice")?;
txn_alice.add_file("file1")?;
txn_alice.add_file("file2")?;
info!("recording file additions");
debug!("working_copy = {:?}", repo_alice);
debug_tree(&txn_alice, "debug_tree")?;
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_bob.rename("file2", "file")?;
txn_bob.move_file("file2", "file")?;
debug!("repo_bob = {:?}", repo_bob.list_files());
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
repo_alice.rename("file1", "file")?;
txn_alice.move_file("file1", "file")?;
debug!("repo_bob = {:?}", repo_alice.list_files());
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
let env_charlie = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_charlie = env_charlie.mut_txn_begin();
let mut channel_charlie = txn_charlie.open_or_create_channel("charlie").unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
repo_charlie.rename("file1", "file3")?;
txn_charlie.move_file("file1", "file3")?;
let charlie_h = record_all(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
)
.unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie1")?;
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, bob_h)?;
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, alice_h)?;
output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie2")?;
let mut files_charlie = repo_charlie.list_files();
files_charlie.sort();
assert_eq!(files_charlie[0], "file");
assert!(files_charlie[1] == "file3" || files_charlie[1].starts_with("file."));
debug!("files_charlie {:?}", files_charlie);
repo_charlie.rename(&files_charlie[1], "file3")?;
txn_charlie.move_file(&files_charlie[1], "file3")?;
let _charlie_solution = record_all(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
)
.unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie3")?;
output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
let mut files_charlie = repo_charlie.list_files();
files_charlie.sort();
assert_eq!(files_charlie, &["file", "file3"]);
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, charlie_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
let mut files_alice = repo_alice.list_files();
files_alice.sort();
debug!("files_alice {:?}", files_alice);
repo_alice.remove_path(&files_alice[1]).unwrap();
let _alice_solution = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, charlie_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
let files_bob = repo_bob.list_files();
debug!("files_bob {:?}", files_bob);
repo_bob.remove_path(&files_bob[1]).unwrap();
let _bob_solution =
record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob3")?;
Ok(())
}
#[test]
fn zombie_file_test() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let contents2 = b"a\nb\nc\nx\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file("a/b/c/file", contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
txn_alice.add_file("a/b/c/file").unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_alice.remove_path("a/b")?;
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.write_file::<_, std::io::Error, _>("a/b/c/file", |w| {
w.write_all(contents2)?;
Ok(())
})?;
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
debug!("alice2");
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
let files_alice = repo_alice.list_files();
assert_eq!(files_alice, vec!["a", "a/b", "a/b/c", "a/b/c/file"]);
for x in txn_alice
.iter_tree(
OwnedPathId {
parent_inode: Inode::ROOT,
basename: crate::small_string::SmallString::new(),
},
None,
)
.unwrap()
{
debug!("x = {:?}", x);
}
debug!("recording a solution");
let alice_solution = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("repo_alice = {:?}", repo_alice.list_files());
debug!("repo_bob = {:?}", repo_bob.list_files());
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_solution)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
let files_bob = repo_bob.list_files();
assert_eq!(files_bob, vec!["a", "a/b", "a/b/c", "a/b/c/file"]);
Ok(())
}
#[test]
fn rename_zombie_file() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let contents2 = b"a\nb\nc\nx\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file("a/b/c/file", contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
txn_alice.add_file("a/b/c/file").unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_alice.remove_path("a/b")?;
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.rename("a/b/c/file", "a/b/c/file2")?;
repo_bob.write_file::<_, std::io::Error, _>("a/b/c/file2", |w| {
w.write_all(contents2)?;
Ok(())
})?;
txn_bob.move_file("a/b/c/file", "a/b/c/file2")?;
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
debug!("alice2");
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
let files_alice = repo_alice.list_files();
debug!("Alice records {:?}", files_alice);
repo_alice.rename("a/b/c/file", "a/b/c/file2").unwrap_or(());
txn_alice
.move_file("a/b/c/file", "a/b/c/file2")
.unwrap_or(());
let alice_solution = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice4")?;
debug!("Alice recorded {:?}", alice_solution);
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("repo_alice = {:?}", repo_alice.list_files());
debug!("repo_bob = {:?}", repo_bob.list_files());
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_solution)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob3")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
let files_bob = repo_bob.list_files();
assert!(["a", "a/b", "a/b/c", "a/b/c/file2"]
.iter()
.all(|n| files_bob.iter().any(|m| m == n)));
Ok(())
}
#[test]
fn rename_zombie_dir() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let contents2 = b"a\nb\nc\nx\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
repo_alice.add_file("a/b/c/file", contents.to_vec());
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
txn_alice.add_file("a/b/c/file").unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_alice.remove_path("a/b")?;
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.rename("a/b/c", "a/b/d")?;
repo_bob.write_file::<_, std::io::Error, _>("a/b/d/file", |w| {
w.write_all(contents2)?;
Ok(())
})?;
txn_bob.move_file("a/b/c", "a/b/d")?;
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
debug!("alice2");
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
let files_alice = repo_alice.list_files();
if files_alice.iter().any(|x| x == "a/b/d/file") {
txn_alice.add_file("a/b/d/file").unwrap_or(());
} else {
assert!(files_alice.iter().any(|x| x == "a/b/c/file"));
txn_alice.move_file("a/b/c", "a/b/d").unwrap();
repo_alice.rename("a/b/c", "a/b/d").unwrap();
}
debug!("Alice records");
let alice_solution = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice4")?;
debug!("Alice recorded {:?}", alice_solution);
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("repo_alice = {:?}", repo_alice.list_files());
debug!("repo_bob = {:?}", repo_bob.list_files());
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_solution)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob3")?;
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
let files_bob = repo_bob.list_files();
debug!("files_bob = {:?}", files_bob);
assert!(["a", "a/b", "a/b/d", "a/b/d/file"]
.iter()
.all(|n| files_bob.iter().any(|m| m == n)));
Ok(())
}
#[test]
fn double_zombie_file() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let contents2 = b"a\nb\nc\nx\nd\ne\nf\n";
let contents3 = b"a\nby\n\nc\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let mut repo_charlie = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let env_charlie = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_charlie = env_charlie.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
repo_alice.add_file("a/b/c/file", contents.to_vec());
txn_alice.add_file("a/b/c/file").unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
let mut channel_charlie = txn_charlie.open_or_create_channel("charlie").unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, init_h).unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie0")?;
if !conflicts.is_empty() {
panic!("charlie has conflicts: {:?}", conflicts);
}
repo_alice.remove_path("a/b")?;
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
repo_bob.write_file::<_, std::io::Error, _>("a/b/c/file", |w| {
w.write_all(contents2)?;
Ok(())
})?;
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
repo_charlie.write_file::<_, std::io::Error, _>("a/b/c/file", |w| {
w.write_all(contents3)?;
Ok(())
})?;
let charlie_h = record_all(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
)
.unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie1")?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, charlie_h)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
debug!("alice2");
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
let files_alice = repo_alice.list_files();
assert_eq!(files_alice, vec!["a", "a/b", "a/b/c", "a/b/c/file"]);
assert_eq!(conflicts.len(), 5);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b"),
ref c => panic!("unexpected conflict {:#?}", c),
}
let mut buf = Vec::new();
repo_alice.read_file("a/b/c/file", &mut buf)?;
repo_alice.write_file::<_, std::io::Error, _>("a/b/c/file", |w| {
for l in std::str::from_utf8(&buf).unwrap().lines() {
if l.len() < 10 {
writeln!(w, "{}", l)?
}
}
Ok(())
})?;
let alice_solution = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, charlie_h)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
assert_eq!(conflicts.len(), 5);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b"),
ref c => panic!("unexpected conflict {:#?}", c),
}
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_solution)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob3")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("bob has conflicts: {:?}", conflicts);
}
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, bob_h)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie2")?;
debug!("charlie applies Alice's change");
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, alice_h)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie3")?;
let conflicts = output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
assert_eq!(conflicts.len(), 5);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b"),
ref c => panic!("unexpected conflict {:#?}", c),
}
debug!("charlie applies Alice's solution");
apply::apply_change(
&changes,
&mut txn_charlie,
&mut channel_charlie,
alice_solution,
)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie4")?;
let conflicts = output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("charlie has conflicts: {:?}", conflicts);
}
Ok(())
}
#[test]
fn zombie_file_post_resolve() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let contents = b"a\nb\nc\nd\ne\nf\n";
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let mut repo_charlie = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let env_charlie = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_charlie = env_charlie.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("alice").unwrap();
repo_alice.add_file("a/b/c/file", contents.to_vec());
txn_alice.add_file("a/b/c/file").unwrap();
let init_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice0")?;
repo_alice.rename("a/b/c/file", "a/b/c/alice")?;
txn_alice.move_file("a/b/c/file", "a/b/c/alice")?;
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1")?;
let mut channel_bob = txn_bob.open_or_create_channel("bob").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, init_h).unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0")?;
repo_bob.remove_path("a/b/c/file")?;
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h).unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("conflicts = {:#?}", conflicts);
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b/c/alice"),
ref c => panic!("unexpected conflict {:#?}", c),
}
debug!("Bob resolves");
let bob_resolution =
record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "").unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("Bob has conflicts: {:?}", conflicts);
}
debug!("Alice applies Bob's resolution");
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h).unwrap();
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_resolution).unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2")?;
if !conflicts.is_empty() {
panic!("Alice has conflicts: {:?}", conflicts);
}
let mut channel_charlie = txn_charlie.open_or_create_channel("charlie").unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, init_h).unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, alice_h).unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie0")?;
if !conflicts.is_empty() {
panic!("charlie has conflicts: {:?}", conflicts);
}
debug!("Charlie applies Alice's move and deletes");
repo_charlie.remove_path("a/b/c/alice")?;
let charlie_h = record_all(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
)
.unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie1")?;
debug!("Charlie applies Bob's deletion");
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, bob_h).unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie2")?;
debug!("Charlie applies Bob's resolution");
apply::apply_change(
&changes,
&mut txn_charlie,
&mut channel_charlie,
bob_resolution,
)
.unwrap();
debug_to_file(&txn_charlie, &channel_charlie.borrow(), "debug_charlie3")?;
let conflicts = output::output_repository_no_pending(
&mut repo_charlie,
&changes,
&mut txn_charlie,
&mut channel_charlie,
"",
true,
)?;
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "a/b/c/alice"),
ref c => panic!("unexpected conflict {:#?}", c),
}
debug!("Alice applies Charlie's deletion");
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, charlie_h).unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3")?;
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert!(path == "a/b/c/file" || path == "a/b/c/alice"),
ref c => panic!("unexpected conflict {:#?}", c),
}
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, charlie_h).unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob3")?;
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert!(path == "a/b/c/file" || path == "a/b/c/alice"),
ref c => panic!("unexpected conflict {:#?}", c),
}
Ok(())
}
#[test]
fn move_vs_delete_test() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("main")?;
repo_alice.add_file("file", b"a\n".to_vec());
txn_alice.add_file("file")?;
let init = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_bob = txn_bob.open_or_create_channel("main")?;
txn_bob
.apply_change(&changes, &mut channel_bob, init)
.unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
repo_alice.rename("file", "alice/file").unwrap_or(());
txn_alice.move_file("file", "alice/file").unwrap_or(());
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1").unwrap();
repo_bob.remove_path("file").unwrap_or(());
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0").unwrap();
debug!("Bob applies Alice's change");
txn_bob
.apply_change(&changes, &mut channel_bob, alice_h)
.unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("conflicts = {:#?}", conflicts);
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "alice/file"),
ref c => panic!("unexpected conflict {:#?}", c),
}
let files = repo_bob.list_files();
if files.iter().any(|f| f == "alice/file") {
repo_bob.remove_path("bob").unwrap()
} else {
repo_bob.remove_path("alice").unwrap()
}
let resolution = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("Bob has conflicts: {:?}", conflicts);
}
debug!("Alice applies Bob's change");
txn_alice
.apply_change(&changes, &mut channel_alice, bob_h)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "alice/file"),
ref c => panic!("unexpected conflict {:#?}", c),
}
debug!("Alice applies Bob's resolution");
txn_alice
.apply_change(&changes, &mut channel_alice, resolution)
.unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3").unwrap();
if !conflicts.is_empty() {
panic!("Alice has conflicts: {:?}", conflicts);
}
Ok(())
}
#[test]
fn delete_zombie_test() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("main")?;
repo_alice.add_file("file", b"a\nb\nc\nd\n".to_vec());
txn_alice.add_file("file")?;
let init = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_bob = txn_bob.open_or_create_channel("main")?;
txn_bob
.apply_change(&changes, &mut channel_bob, init)
.unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
repo_alice.write_file::<_, std::io::Error, _>("file", |w| {
w.write_all(b"a\nb\nx\nc\nd\n")?;
Ok(())
})?;
record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1").unwrap();
repo_bob.write_file::<_, std::io::Error, _>("file", |w| {
w.write_all(b"a\nd\n")?;
Ok(())
})?;
let bob_h1 = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0").unwrap();
repo_bob.remove_path("file").unwrap_or(());
let bob_h2 = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1").unwrap();
debug!("Alice applies Bob's change");
txn_alice
.apply_change(&changes, &mut channel_alice, bob_h1)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2").unwrap();
debug!("Applying bob_h2");
txn_alice
.apply_change(&changes, &mut channel_alice, bob_h2)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3").unwrap();
let (alive, reachable) = check_alive(&txn_alice, &channel_alice.borrow().graph);
if !alive.is_empty() {
panic!("alive (bob0): {:?}", alive);
}
if !reachable.is_empty() {
panic!("reachable (bob0): {:?}", reachable);
}
crate::unrecord::unrecord(&mut txn_alice, &mut channel_alice, &changes, &bob_h2).unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice4").unwrap();
output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
let mut buf = Vec::new();
repo_alice.read_file("file", &mut buf)?;
debug!("file = {:?}", std::str::from_utf8(&buf));
Ok(())
}
#[test]
fn move_into_deleted_test() -> Result<(), anyhow::Error> {
env_logger::try_init().unwrap_or(());
let mut repo_alice = working_copy::memory::Memory::new();
let mut repo_bob = working_copy::memory::Memory::new();
let changes = changestore::memory::Memory::new();
let env_alice = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_alice = env_alice.mut_txn_begin();
let mut channel_alice = txn_alice.open_or_create_channel("main")?;
repo_alice.add_file("file", b"a\n".to_vec());
repo_alice.add_dir("dir");
txn_alice.add_file("file")?;
txn_alice.add_dir("dir")?;
let init = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
let env_bob = pristine::sanakirja::Pristine::new_anon()?;
let mut txn_bob = env_bob.mut_txn_begin();
let mut channel_bob = txn_bob.open_or_create_channel("main")?;
txn_bob
.apply_change(&changes, &mut channel_bob, init)
.unwrap();
output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
repo_alice.rename("file", "dir/file").unwrap_or(());
txn_alice.move_file("file", "dir/file").unwrap_or(());
let alice_h = record_all(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice1").unwrap();
repo_bob.remove_path("dir").unwrap_or(());
let bob_h = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob0").unwrap();
debug!("Bob applies Alice's change");
txn_bob
.apply_change(&changes, &mut channel_bob, alice_h)
.unwrap();
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob1").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
debug!("conflicts = {:#?}", conflicts);
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "dir"),
ref c => panic!("unexpected conflict {:#?}", c),
}
let resolution = record_all(&mut repo_bob, &changes, &mut txn_bob, &mut channel_bob, "")?;
debug_to_file(&txn_bob, &channel_bob.borrow(), "debug_bob2").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_bob,
&changes,
&mut txn_bob,
&mut channel_bob,
"",
true,
)?;
if !conflicts.is_empty() {
panic!("Bob has conflicts: {:?}", conflicts);
}
debug!("Alice applies Bob's change");
txn_alice
.apply_change(&changes, &mut channel_alice, bob_h)
.unwrap();
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice2").unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
assert_eq!(conflicts.len(), 1);
match conflicts[0] {
Conflict::ZombieFile { ref path } => assert_eq!(path, "dir"),
ref c => panic!("unexpected conflict {:#?}", c),
}
debug!("Alice applies Bob's resolution");
txn_alice
.apply_change(&changes, &mut channel_alice, resolution)
.unwrap();
let conflicts = output::output_repository_no_pending(
&mut repo_alice,
&changes,
&mut txn_alice,
&mut channel_alice,
"",
true,
)?;
debug_to_file(&txn_alice, &channel_alice.borrow(), "debug_alice3").unwrap();
if !conflicts.is_empty() {
panic!("Alice has conflicts: {:?}", conflicts);
}
Ok(())
}