use peat_btle::document::PeatDocument;
use peat_btle::sync::crdt::{Peripheral, PeripheralType};
use peat_btle::NodeId;
const TEST_TIMESTAMP: u64 = 1705276800000;
#[test]
fn test_emergency_event_creation() {
let mut doc = PeatDocument::new(NodeId::new(0x111));
let peripheral = Peripheral::new(0x111, PeripheralType::SoldierSensor);
doc.peripheral = Some(peripheral);
let known_peers = vec![0x222, 0x333, 0x444];
doc.set_emergency(0x111, TEST_TIMESTAMP, &known_peers);
assert!(doc.has_emergency());
let emergency = doc.get_emergency().unwrap();
assert_eq!(emergency.source_node(), 0x111);
assert_eq!(emergency.timestamp(), TEST_TIMESTAMP);
assert!(!emergency.has_acked(0x222));
assert!(!emergency.has_acked(0x333));
assert!(!emergency.has_acked(0x444));
}
#[test]
fn test_emergency_ack_recording() {
let mut doc = PeatDocument::new(NodeId::new(0x111));
doc.set_emergency(0x111, TEST_TIMESTAMP, &[0x222, 0x333]);
let changed = doc.ack_emergency(0x222);
assert!(changed);
let emergency = doc.get_emergency().unwrap();
assert!(emergency.has_acked(0x222));
assert!(!emergency.has_acked(0x333));
let changed = doc.ack_emergency(0x222);
assert!(!changed);
}
#[test]
fn test_emergency_propagation() {
let mut doc_a = PeatDocument::new(NodeId::new(0xAAA));
let peripheral = Peripheral::new(0xAAA, PeripheralType::SoldierSensor);
doc_a.peripheral = Some(peripheral);
doc_a.set_emergency(0xAAA, TEST_TIMESTAMP, &[0xBBB, 0xCCC]);
let mut doc_b = PeatDocument::new(NodeId::new(0xBBB));
let data = doc_a.encode();
let received = PeatDocument::decode(&data).unwrap();
let changed = doc_b.merge(&received);
assert!(changed);
assert!(doc_b.has_emergency());
let emergency = doc_b.get_emergency().unwrap();
assert_eq!(emergency.source_node(), 0xAAA);
}
#[test]
fn test_ack_propagation() {
let known_peers = vec![0xBBB, 0xCCC];
let mut doc_a = PeatDocument::new(NodeId::new(0xAAA));
doc_a.set_emergency(0xAAA, TEST_TIMESTAMP, &known_peers);
let mut doc_b = PeatDocument::new(NodeId::new(0xBBB));
let mut doc_c = PeatDocument::new(NodeId::new(0xCCC));
let data = doc_a.encode();
doc_b.merge(&PeatDocument::decode(&data).unwrap());
doc_c.merge(&PeatDocument::decode(&data).unwrap());
doc_b.ack_emergency(0xBBB);
let data = doc_b.encode();
let changed = doc_a.merge(&PeatDocument::decode(&data).unwrap());
assert!(changed);
let emergency = doc_a.get_emergency().unwrap();
assert!(emergency.has_acked(0xBBB));
assert!(!emergency.has_acked(0xCCC));
doc_c.ack_emergency(0xCCC);
let data = doc_c.encode();
doc_a.merge(&PeatDocument::decode(&data).unwrap());
let emergency = doc_a.get_emergency().unwrap();
assert!(emergency.has_acked(0xBBB));
assert!(emergency.has_acked(0xCCC));
}
#[test]
fn test_ack_merge_from_multiple_paths() {
let known_peers = vec![0xBBB, 0xCCC, 0xDDD];
let mut doc_a = PeatDocument::new(NodeId::new(0xAAA));
doc_a.set_emergency(0xAAA, TEST_TIMESTAMP, &known_peers);
let mut doc_b = PeatDocument::new(NodeId::new(0xBBB));
let mut doc_c = PeatDocument::new(NodeId::new(0xCCC));
let mut doc_d = PeatDocument::new(NodeId::new(0xDDD));
let data = doc_a.encode();
doc_b.merge(&PeatDocument::decode(&data).unwrap());
doc_c.merge(&PeatDocument::decode(&data).unwrap());
doc_d.merge(&PeatDocument::decode(&data).unwrap());
doc_b.ack_emergency(0xBBB);
doc_c.ack_emergency(0xCCC);
let data_b = doc_b.encode();
let data_c = doc_c.encode();
doc_d.merge(&PeatDocument::decode(&data_b).unwrap());
doc_d.merge(&PeatDocument::decode(&data_c).unwrap());
let emergency = doc_d.get_emergency().unwrap();
assert!(emergency.has_acked(0xBBB));
assert!(emergency.has_acked(0xCCC));
assert!(!emergency.has_acked(0xDDD));
doc_d.ack_emergency(0xDDD);
let data_d = doc_d.encode();
doc_a.merge(&PeatDocument::decode(&data_d).unwrap());
let emergency = doc_a.get_emergency().unwrap();
assert!(emergency.has_acked(0xBBB));
assert!(emergency.has_acked(0xCCC));
assert!(emergency.has_acked(0xDDD));
}
#[test]
fn test_emergency_clear() {
let mut doc = PeatDocument::new(NodeId::new(0x111));
doc.set_emergency(0x111, TEST_TIMESTAMP, &[0x222]);
assert!(doc.has_emergency());
doc.clear_emergency();
assert!(!doc.has_emergency());
assert!(doc.get_emergency().is_none());
}
#[test]
fn test_emergency_supersede() {
let known_peers = vec![0xBBB, 0xCCC];
let mut doc_a = PeatDocument::new(NodeId::new(0xAAA));
doc_a.set_emergency(0xAAA, TEST_TIMESTAMP, &known_peers);
let mut doc_b = PeatDocument::new(NodeId::new(0xBBB));
doc_b.merge(&PeatDocument::decode(&doc_a.encode()).unwrap());
doc_b.set_emergency(0xBBB, TEST_TIMESTAMP + 1000, &known_peers);
doc_a.merge(&PeatDocument::decode(&doc_b.encode()).unwrap());
let emergency = doc_a.get_emergency().unwrap();
assert_eq!(emergency.source_node(), 0xBBB);
assert_eq!(emergency.timestamp(), TEST_TIMESTAMP + 1000);
}
#[test]
fn test_emergency_document_size() {
use peat_btle::document::TARGET_DOCUMENT_SIZE;
let mut doc = PeatDocument::new(NodeId::new(0x111));
let peripheral = Peripheral::new(0x111, PeripheralType::SoldierSensor);
doc.peripheral = Some(peripheral);
doc.set_emergency(0x111, TEST_TIMESTAMP, &[0x222, 0x333, 0x444]);
let size = doc.encoded_size();
assert!(
size < TARGET_DOCUMENT_SIZE,
"Small emergency should fit: {} bytes",
size
);
let data = doc.encode();
let decoded = PeatDocument::decode(&data).unwrap();
assert!(decoded.has_emergency());
assert_eq!(decoded.get_emergency().unwrap().source_node(), 0x111);
}
#[test]
fn test_ack_idempotent_merge() {
let mut doc_a = PeatDocument::new(NodeId::new(0xAAA));
doc_a.set_emergency(0xAAA, TEST_TIMESTAMP, &[0xBBB]);
let mut doc_b = PeatDocument::new(NodeId::new(0xBBB));
doc_b.merge(&PeatDocument::decode(&doc_a.encode()).unwrap());
doc_b.ack_emergency(0xBBB);
for _ in 0..5 {
doc_a.merge(&PeatDocument::decode(&doc_b.encode()).unwrap());
}
let emergency = doc_a.get_emergency().unwrap();
assert!(emergency.has_acked(0xBBB));
let acked_count = [0xBBB]
.iter()
.filter(|&&id| emergency.has_acked(id))
.count();
assert_eq!(acked_count, 1);
}