use std::error::Error;
use haematite::branch::ShardRef;
use super::*;
use crate::serve::protocol::Version;
type TestResult = Result<(), Box<dyn Error>>;
fn captured(branch: &str, generation: u64, sequence: u64) -> Captured {
Captured {
branch: branch.to_owned(),
version: Version {
generation,
sequence,
},
shards: vec![ShardRef {
shard_id: 0,
fork_anchor: Hash::of(b"anchor"),
head: Hash::of(b"head"),
}],
}
}
fn pins() -> Result<Pins, Failure> {
Pins::new(
&captured("main", 1, 2),
&captured("main", 1, 3),
&captured("feature", 4, 5),
)
}
#[test]
fn full_edge_destination_changes_the_choice_token() -> TestResult {
let pins = pins()?;
let first = pins.token(b"e\0records\0a\0links\0records\0b", None, None, Some(b"{}"))?;
let second = pins.token(b"e\0records\0a\0links\0records\0c", None, None, Some(b"{}"))?;
assert_ne!(first, second);
Ok(())
}
#[test]
fn unchanged_pins_and_raw_values_mint_the_same_token() -> TestResult {
let key = b"e\0records\0a\0links\0records\0b";
let first = pins()?.token(key, Some(b"{}"), None, Some(b"{\"weight\":2}"))?;
let second = pins()?.token(key, Some(b"{}"), None, Some(b"{\"weight\":2}"))?;
assert_eq!(first, second);
assert_eq!(first.len(), "merge-choice-v1:".len() + 64);
Ok(())
}
#[test]
fn changed_source_raw_bytes_change_the_token_at_the_same_pins() -> TestResult {
let pins = pins()?;
let key = b"e\0records\0a\0links\0records\0b";
let first = pins.token(key, None, None, Some(b"{\"weight\":1}"))?;
let second = pins.token(key, None, None, Some(b"{\"weight\":2}"))?;
assert_ne!(first, second);
Ok(())
}
#[test]
fn absent_and_present_empty_values_have_different_tokens() -> TestResult {
let pins = pins()?;
let key = b"d\0records\0a";
assert_ne!(
pins.token(key, None, None, None)?,
pins.token(key, None, None, Some(b""))?
);
Ok(())
}
#[test]
fn every_value_slot_is_bound_without_json_normalisation() -> TestResult {
let pins = pins()?;
let key = b"d\0records\0a";
let first = pins.token(key, Some(b"{}"), Some(b"{}"), Some(b"{}"))?;
assert_ne!(
first,
pins.token(key, Some(b"{ }"), Some(b"{}"), Some(b"{}"))?
);
assert_ne!(
first,
pins.token(key, Some(b"{}"), Some(b"{ }"), Some(b"{}"))?
);
assert_ne!(
first,
pins.token(key, Some(b"{}"), Some(b"{}"), Some(b"{ }"))?
);
Ok(())
}
#[test]
fn branch_versions_and_physical_roots_are_bound() -> TestResult {
let origin = captured("main", 1, 2);
let target = captured("main", 1, 3);
let source = captured("feature", 4, 5);
let key = b"d\0records\0a";
let first = Pins::new(&origin, &target, &source)?.token(key, None, None, Some(b"{}"))?;
for slot in [0, 1, 2] {
for field in 0..5 {
let mut changed = [origin.clone(), target.clone(), source.clone()];
let at = &mut changed[slot];
match field {
0 => at.branch.push('x'),
1 => at.version.generation += 1,
2 => at.version.sequence += 1,
3 => at.shards[0].shard_id += 1,
_ => at.shards[0].head = Hash::of(b"other head"),
}
let token = Pins::new(&changed[0], &changed[1], &changed[2])?.token(
key,
None,
None,
Some(b"{}"),
)?;
assert_ne!(first, token);
}
}
Ok(())
}
#[test]
fn live_and_kept_captures_of_the_same_read_roots_have_the_same_token() -> TestResult {
let live = [
captured("main", 1, 2),
captured("main", 1, 3),
captured("feature", 4, 5),
];
let mut kept = live.clone();
for at in &mut kept {
for shard in &mut at.shards {
shard.fork_anchor = shard.head;
}
}
let key = b"d\0records\0a";
assert_eq!(
Pins::new(&live[0], &live[1], &live[2])?.token(key, None, None, Some(b"{}"))?,
Pins::new(&kept[0], &kept[1], &kept[2])?.token(key, None, None, Some(b"{}"))?
);
Ok(())
}