#![no_std]
extern crate alloc;
#[cfg(not(feature = "zkvm"))]
use alloc::collections::BTreeSet;
use alloc::collections::{BTreeMap, BinaryHeap};
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp::Ordering;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "std")]
pub use std::collections::HashMap;
#[cfg(not(feature = "std"))]
pub use hashbrown::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
pub enum StateResVersion {
V1,
V2,
V2_1,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LeanEvent {
pub event_id: String,
#[serde(rename = "type")]
pub event_type: String,
#[serde(default)]
pub state_key: String,
#[serde(default)]
pub power_level: i64,
pub origin_server_ts: u64,
#[serde(default)]
pub sender: String,
#[serde(default)]
pub content: Value,
#[serde(default)]
pub prev_events: Vec<String>,
#[serde(default)]
pub auth_events: Vec<String>,
#[serde(default)]
pub depth: u64, }
impl PartialEq for LeanEvent {
fn eq(&self, other: &Self) -> bool {
self.event_id == other.event_id
}
}
impl Eq for LeanEvent {}
impl Ord for LeanEvent {
fn cmp(&self, other: &Self) -> Ordering {
self.event_id.cmp(&other.event_id)
}
}
impl PartialOrd for LeanEvent {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Copy)]
struct SortPriority<'a> {
event: &'a LeanEvent,
version: StateResVersion,
}
impl<'a> PartialEq for SortPriority<'a> {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<'a> Eq for SortPriority<'a> {}
impl<'a> Ord for SortPriority<'a> {
fn cmp(&self, other: &Self) -> Ordering {
match self.version {
StateResVersion::V1 => {
match other.event.depth.cmp(&self.event.depth) {
Ordering::Equal => other.event.event_id.cmp(&self.event.event_id),
ord => ord,
}
}
StateResVersion::V2 | StateResVersion::V2_1 => {
match other.event.power_level.cmp(&self.event.power_level) {
Ordering::Equal => {
match other
.event
.origin_server_ts
.cmp(&self.event.origin_server_ts)
{
Ordering::Equal => {
other.event.event_id.cmp(&self.event.event_id)
}
ord => ord,
}
}
ord => ord,
}
}
}
}
}
impl<'a> PartialOrd for SortPriority<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
pub fn lean_kahn_sort(
events: &HashMap<String, LeanEvent>,
version: StateResVersion,
) -> Vec<String> {
let mut in_degree: HashMap<String, usize> = HashMap::new();
let mut adjacency: HashMap<String, Vec<String>> = HashMap::new();
for (id, event) in events {
in_degree.entry(id.clone()).or_insert(0);
for auth in &event.auth_events {
if events.contains_key(auth) {
adjacency.entry(auth.clone()).or_default().push(id.clone());
*in_degree.entry(id.clone()).or_insert(0) += 1;
}
}
}
let mut queue: BinaryHeap<SortPriority> = BinaryHeap::new();
for (id, °ree) in &in_degree {
if degree == 0 {
if let Some(event) = events.get(id) {
queue.push(SortPriority { event, version });
}
}
}
let mut result = Vec::new();
while let Some(priority) = queue.pop() {
let event = priority.event;
result.push(event.event_id.clone());
if let Some(neighbors) = adjacency.get(&event.event_id) {
for next_id in neighbors {
let degree = in_degree.get_mut(next_id).unwrap();
*degree -= 1;
if *degree == 0 {
queue.push(SortPriority {
event: events.get(next_id).unwrap(),
version,
});
}
}
}
}
if result.len() != events.len() {
return Vec::new();
}
result
}
pub fn resolve_lean(
unconflicted_state: BTreeMap<(String, String), String>,
conflicted_events: HashMap<String, LeanEvent>,
version: StateResVersion,
) -> BTreeMap<(String, String), String> {
let (mut resolved, sort_set) = match version {
StateResVersion::V2_1 => {
(BTreeMap::new(), conflicted_events.clone())
}
_ => (unconflicted_state, conflicted_events),
};
let sorted_ids = lean_kahn_sort(&sort_set, version);
for id in sorted_ids {
if let Some(event) = sort_set.get(&id) {
resolved.insert(
(event.event_type.clone(), event.state_key.clone()),
event.event_id.clone(),
);
}
}
resolved
}
#[cfg(not(feature = "zkvm"))] pub fn compute_v2_1_conflicted_subgraph(
auth_graph: &HashMap<String, LeanEvent>,
conflicted_set: &[String],
) -> HashMap<String, LeanEvent> {
let mut backwards_reachable = BTreeSet::new();
let mut forwards_reachable = BTreeSet::new();
let mut b_stack: Vec<String> = conflicted_set.to_vec();
while let Some(node) = b_stack.pop() {
if backwards_reachable.insert(node.clone()) {
if let Some(event) = auth_graph.get(&node) {
b_stack.extend(event.auth_events.clone());
}
}
}
let mut children_map: HashMap<String, Vec<String>> = HashMap::new();
for (id, event) in auth_graph {
for prev in &event.auth_events {
children_map
.entry(prev.clone())
.or_default()
.push(id.clone());
}
}
let mut f_stack: Vec<String> = conflicted_set.to_vec();
while let Some(node) = f_stack.pop() {
if forwards_reachable.insert(node.clone()) {
if let Some(children) = children_map.get(&node) {
f_stack.extend(children.clone());
}
}
}
let mut subgraph = HashMap::new();
let backwards_ids: BTreeSet<String> = backwards_reachable.iter().cloned().collect();
let forwards_ids: BTreeSet<String> = forwards_reachable.iter().cloned().collect();
for id in backwards_ids.intersection(&forwards_ids) {
if let Some(event) = auth_graph.get(id) {
subgraph.insert(id.clone(), event.clone());
}
}
subgraph
}
#[cfg(feature = "zkvm")]
pub fn verify_signature(_public_key: &[u8; 32], _message: &[u8], _signature: &[u8; 64]) {
}
#[cfg(all(feature = "std", not(feature = "zkvm")))]
pub fn verify_signature(public_key: &[u8; 32], message: &[u8], signature: &[u8; 64]) {
use ed25519_consensus::{Signature, VerificationKey};
let vk = VerificationKey::try_from(*public_key).expect("Invalid public key");
let sig = Signature::from(*signature);
vk.verify(&sig, message)
.expect("Signature verification failed");
}
#[cfg(all(not(feature = "std"), not(feature = "zkvm")))]
pub fn verify_signature(_public_key: &[u8; 32], _message: &[u8], _signature: &[u8; 64]) {
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
use alloc::vec;
#[cfg(not(feature = "std"))]
use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
#[test]
fn test_leanevent_deserialization_defaults() {
let json = r#"{
"event_id": "$test",
"type": "m.room.message",
"origin_server_ts": 12345
}"#;
let ev: LeanEvent = serde_json::from_str(json).unwrap();
assert_eq!(ev.event_id, "$test");
assert_eq!(ev.event_type, "m.room.message");
assert_eq!(ev.origin_server_ts, 12345);
assert_eq!(ev.state_key, "");
assert_eq!(ev.power_level, 0);
assert_eq!(ev.sender, "");
assert_eq!(ev.prev_events.len(), 0);
assert_eq!(ev.auth_events.len(), 0);
assert_eq!(ev.depth, 0);
}
#[test]
fn test_sort_priority_v2_tie_break() {
let e_base = LeanEvent {
event_id: "$1".into(),
power_level: 100,
origin_server_ts: 10,
..Default::default()
};
let e_worst_pl = LeanEvent {
event_id: "$2".into(),
power_level: 50,
origin_server_ts: 10,
..Default::default()
};
let p_base = SortPriority {
event: &e_base,
version: StateResVersion::V2,
};
let p_worst_pl = SortPriority {
event: &e_worst_pl,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_worst_pl), Ordering::Less);
let e_earlier_ts = LeanEvent {
event_id: "$3".into(),
power_level: 100,
origin_server_ts: 5,
..Default::default()
};
let p_earlier_ts = SortPriority {
event: &e_earlier_ts,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_earlier_ts), Ordering::Less);
let e_smaller_id = LeanEvent {
event_id: "$0".into(),
power_level: 100,
origin_server_ts: 10,
..Default::default()
};
let p_smaller_id = SortPriority {
event: &e_smaller_id,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_smaller_id), Ordering::Less);
}
#[test]
fn test_v1_resolution_happy_path() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 50,
prev_events: vec![],
auth_events: vec!["A".into()],
depth: 2,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V1);
assert_eq!(sorted, vec!["A", "B"]);
}
#[test]
fn test_v2_1_strict_resolution() {
let mut unconflicted = BTreeMap::new();
unconflicted.insert(
("m.room.member".into(), "@alice:example.com".into()),
"A".into(),
);
let mut conflicted = HashMap::new();
conflicted.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
conflicted.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 50,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let resolved = resolve_lean(unconflicted, conflicted, StateResVersion::V2_1);
assert_eq!(
resolved.get(&("m.room.member".into(), "@alice:example.com".into())),
Some(&"B".into())
);
}
#[test]
fn test_v1_tie_break_by_id() {
let mut events = HashMap::new();
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V1);
assert_eq!(sorted, vec!["A", "B"]);
}
#[test]
fn test_v2_resolution_happy_path() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 10,
..Default::default()
},
);
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert_eq!(sorted, vec!["B", "A"]);
}
#[test]
fn test_v2_deep_tie_break() {
let mut events = HashMap::new();
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert_eq!(sorted, vec!["A", "B"]);
}
#[test]
fn test_v1_v2_v2_1_comparison_determinism() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 10,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 100,
prev_events: vec![],
auth_events: vec![],
depth: 10,
..Default::default()
},
);
let sorted_v1 = lean_kahn_sort(&events, StateResVersion::V1);
let sorted_v2 = lean_kahn_sort(&events, StateResVersion::V2);
let sorted_v2_1 = lean_kahn_sort(&events, StateResVersion::V2_1);
assert_eq!(sorted_v1, vec!["A", "B"]);
assert_eq!(sorted_v2, vec!["A", "B"]);
assert_eq!(sorted_v2_1, vec!["A", "B"]);
}
#[test]
fn test_unhappy_path_cycle_detection() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 100,
prev_events: vec!["B".into()],
auth_events: vec!["B".into()],
depth: 1,
..Default::default()
},
);
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 100,
prev_events: vec!["A".into()],
auth_events: vec!["A".into()],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert!(sorted.is_empty());
}
#[test]
#[cfg(all(feature = "std", not(feature = "zkvm")))]
#[should_panic(expected = "Signature verification failed")]
fn test_signature_verification_failure() {
let pk = [
215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114,
243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
];
let sig = [0u8; 64];
let msg = b"test";
verify_signature(&pk, msg, &sig);
}
#[test]
fn test_serialization_roundtrip() {
let event = LeanEvent {
event_id: "$abc".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 12345,
prev_events: vec![],
auth_events: vec![],
depth: 5,
..Default::default()
};
let serialized = serde_json::to_string(&event).unwrap();
let deserialized: LeanEvent = serde_json::from_str(&serialized).unwrap();
assert_eq!(event, deserialized);
}
#[test]
fn test_partial_ord_implementations() {
let e1 = LeanEvent {
event_id: "a".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let e2 = LeanEvent {
event_id: "b".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
assert!(e1.partial_cmp(&e2).is_some());
let p1 = SortPriority {
event: &e1,
version: StateResVersion::V2,
};
let p2 = SortPriority {
event: &e2,
version: StateResVersion::V2,
};
assert!(p1.partial_cmp(&p2).is_some());
}
#[test]
fn test_trait_coverage() {
let v = StateResVersion::V2;
assert_eq!(v, StateResVersion::V2);
let _ = alloc::format!("{:?}", v);
let e = LeanEvent {
event_id: "a".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let _ = e.clone();
let _ = alloc::format!("{:?}", e);
}
#[test]
fn test_complex_dag_sort() {
let mut events = HashMap::new();
events.insert(
"1".into(),
LeanEvent {
event_id: "1".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"2".into(),
LeanEvent {
event_id: "2".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 20,
prev_events: vec!["1".into()],
auth_events: vec!["1".into()],
depth: 2,
..Default::default()
},
);
events.insert(
"3".into(),
LeanEvent {
event_id: "3".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 15,
prev_events: vec!["1".into()],
auth_events: vec!["1".into()],
depth: 2,
..Default::default()
},
);
events.insert(
"4".into(),
LeanEvent {
event_id: "4".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 10,
origin_server_ts: 30,
prev_events: vec!["2".into(), "3".into()],
auth_events: vec!["2".into(), "3".into()],
depth: 3,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert_eq!(sorted, vec!["1", "3", "2", "4"]);
}
#[test]
fn test_kahn_missing_parents() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec!["MISSING".into()],
auth_events: vec!["MISSING".into()],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert_eq!(sorted, vec!["A"]);
}
#[test]
fn test_resolve_lean_functionality() {
let mut unconflicted = BTreeMap::new();
unconflicted.insert(("type".into(), "key".into()), "id".into());
let conflicted = HashMap::new();
let resolved = resolve_lean(unconflicted.clone(), conflicted, StateResVersion::V2);
assert_eq!(resolved, unconflicted);
}
#[test]
fn test_resolve_lean_v2_1_overlay() {
let mut unconflicted = BTreeMap::new();
unconflicted.insert(("type1".into(), "key1".into()), "id1".into());
unconflicted.insert(("type2".into(), "key2".into()), "id2".into());
let mut conflicted = HashMap::new();
conflicted.insert(
"id1".into(),
LeanEvent {
event_id: "id1".into(),
event_type: "type1".into(),
state_key: "key1".into(),
power_level: 50,
origin_server_ts: 500,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
conflicted.insert(
"id2".into(),
LeanEvent {
event_id: "id2".into(),
event_type: "type2".into(),
state_key: "key2".into(),
power_level: 50,
origin_server_ts: 500,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
conflicted.insert(
"id2_new".into(),
LeanEvent {
event_id: "id2_new".into(),
event_type: "type2".into(),
state_key: "key2".into(),
power_level: 100,
origin_server_ts: 1000,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let resolved = resolve_lean(unconflicted.clone(), conflicted, StateResVersion::V2_1);
assert_eq!(
resolved.get(&("type1".into(), "key1".into())),
Some(&"id1".into())
);
assert_eq!(
resolved.get(&("type2".into(), "key2".into())),
Some(&"id2_new".into())
);
}
fn run_batch_test(
version: StateResVersion,
rows: &[(&str, i64, u64, u64, &[&str])],
expected: &[&str],
) {
let mut events = HashMap::new();
for r in rows {
events.insert(
r.0.to_string(),
LeanEvent {
event_id: r.0.to_string(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: r.1,
origin_server_ts: r.2,
depth: r.3,
prev_events: r.4.iter().map(|s| s.to_string()).collect(),
auth_events: r.4.iter().map(|s| s.to_string()).collect(),
..Default::default()
},
);
}
let result = lean_kahn_sort(&events, version);
assert_eq!(
result,
expected.iter().map(|s| s.to_string()).collect::<Vec<_>>()
);
}
#[test]
fn test_resolution_batch() {
run_batch_test(
StateResVersion::V2,
&[("Alice", 100, 500, 1, &[]), ("Bob", 50, 100, 1, &[])],
&["Bob", "Alice"], );
run_batch_test(
StateResVersion::V1,
&[("Deep", 100, 100, 10, &[]), ("Shallow", 10, 100, 1, &[])],
&["Shallow", "Deep"],
);
}
#[test]
fn test_native_resolution_bootstrap_parity() {
let mut events = HashMap::new();
events.insert(
"1".into(),
LeanEvent {
event_id: "1".into(),
event_type: "m.room.member".into(),
state_key: "@user:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"2".into(),
LeanEvent {
event_id: "2".into(),
event_type: "m.room.member".into(),
state_key: "@user:example.com".into(),
power_level: 0,
origin_server_ts: 20,
prev_events: vec!["1".into()],
auth_events: vec!["1".into()],
depth: 2,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
let mut resolved_state = BTreeMap::new();
for id in sorted {
let ev = events.get(&id).unwrap();
let key = (ev.event_type.clone(), ev.state_key.clone());
resolved_state.insert(key, ev.event_id.clone());
}
assert_eq!(
resolved_state.get(&("m.room.member".to_string(), "@user:example.com".to_string())),
Some(&"2".to_string())
);
}
#[test]
fn test_enum_coverage() {
let v = StateResVersion::V2;
let v2 = v;
assert_eq!(v, v2);
let debug_str = alloc::format!("{:?}", v);
assert!(debug_str.contains("V2"));
}
#[test]
fn test_event_traits_coverage() {
let e = LeanEvent {
event_id: "a".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let e2 = e.clone();
assert_eq!(e, e2);
let debug_str = alloc::format!("{:?}", e);
assert!(debug_str.contains("event_id"));
}
#[test]
fn test_sort_priority_traits() {
let e = LeanEvent {
event_id: "a".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let p = SortPriority {
event: &e,
version: StateResVersion::V2,
};
let p2 = p;
assert_eq!(p, p2);
let debug_str = alloc::format!("{:?}", p);
assert!(debug_str.contains("version"));
}
#[test]
fn test_v1_equal_depth_tie_break() {
let mut events = HashMap::new();
events.insert(
"B".into(),
LeanEvent {
event_id: "B".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 0,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V1);
assert_eq!(sorted, vec!["A", "B"]);
}
#[test]
fn test_kahn_no_neighbors() {
let mut events = HashMap::new();
events.insert(
"1".into(),
LeanEvent {
event_id: "1".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2);
assert_eq!(sorted, vec!["1"]);
}
#[test]
fn test_v2_1_full_coverage() {
let mut events = HashMap::new();
events.insert(
"A".into(),
LeanEvent {
event_id: "A".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
},
);
let sorted = lean_kahn_sort(&events, StateResVersion::V2_1);
assert_eq!(sorted, vec!["A"]);
}
#[test]
fn test_total_order_properties() {
let e1 = LeanEvent {
event_id: "a".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let e2 = LeanEvent {
event_id: "b".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 100,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
let e3 = LeanEvent {
event_id: "c".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 10,
prev_events: vec![],
auth_events: vec![],
depth: 1,
..Default::default()
};
assert_eq!(e1.cmp(&e1), Ordering::Equal);
assert!(e1 <= e1);
assert!(e1 <= e2 || e2 <= e1);
if e1 <= e2 && e2 <= e3 {
assert!(e1 <= e3);
}
let e1_copy = e1.clone();
if e1 <= e1_copy && e1_copy <= e1 {
assert_eq!(e1, e1_copy);
}
}
#[test]
fn test_coverage_booster_all_branches() {
let e_base = LeanEvent {
event_id: "m".into(),
event_type: "m.room.member".into(),
state_key: "@alice:example.com".into(),
power_level: 50,
origin_server_ts: 50,
prev_events: vec![],
auth_events: vec![],
depth: 50,
..Default::default()
};
let p_base = SortPriority {
event: &e_base,
version: StateResVersion::V2,
};
let e_high_power = LeanEvent {
power_level: 100,
..e_base.clone()
};
let p_high_power = SortPriority {
event: &e_high_power,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_high_power), Ordering::Greater);
let e_early_ts = LeanEvent {
origin_server_ts: 10,
..e_base.clone()
};
let p_early_ts = SortPriority {
event: &e_early_ts,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_early_ts), Ordering::Less);
let e_early_id = LeanEvent {
event_id: "a".into(),
..e_base.clone()
};
let p_early_id = SortPriority {
event: &e_early_id,
version: StateResVersion::V2,
};
assert_eq!(p_base.cmp(&p_early_id), Ordering::Less);
let p_v1_base = SortPriority {
event: &e_base,
version: StateResVersion::V1,
};
let e_shallow = LeanEvent {
depth: 1,
..e_base.clone()
};
let p_shallow = SortPriority {
event: &e_shallow,
version: StateResVersion::V1,
};
assert_eq!(p_v1_base.cmp(&p_shallow), Ordering::Less);
let p_v1_early_id = SortPriority {
event: &e_early_id,
version: StateResVersion::V1,
};
assert_eq!(p_v1_base.cmp(&p_v1_early_id), Ordering::Less);
assert_eq!(p_v1_base.cmp(&p_v1_base), Ordering::Equal);
}
}