#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::time::{Duration, Instant};
use tf_tree::{AwaitError, Capacity, EdgeCfg, Iso3, LookupError, Stamp, SystemDomain, TreeBuilder};
fn stamp() -> Stamp<SystemDomain> {
Stamp::from_nanos(0)
}
#[test]
fn await_frames_on_a_writable_tree_is_refused_immediately() {
let tree = TreeBuilder::new()
.static_edge("map", "odom", &Iso3::IDENTITY)
.frame_headroom(1)
.build()
.unwrap();
assert!(
tree.is_writable(),
"a heap tree is writable by construction"
);
let started = Instant::now();
let got = tree.await_frames(["map", "nobody_declared_this"], Duration::from_secs(5));
let elapsed = started.elapsed();
assert_eq!(got, Err(AwaitError::WritableTree), "elapsed {elapsed:?}");
assert!(
elapsed < Duration::from_millis(10),
"the refusal is a property of the handle and must not cost a poll: {elapsed:?}"
);
assert!(tree.frame("nobody_declared_this").is_ok());
}
#[test]
fn await_frames_of_nothing_is_not_a_special_case() {
let tree = TreeBuilder::new()
.static_edge("map", "odom", &Iso3::IDENTITY)
.build()
.unwrap();
assert_eq!(
tree.await_frames([], Duration::from_secs(5)),
Err(AwaitError::WritableTree)
);
}
#[test]
fn an_undeclared_frame_describes_the_tree_it_is_not_in() {
let tree = TreeBuilder::new()
.static_edge("map", "odom", &Iso3::IDENTITY)
.static_edge("odom", "base_link", &Iso3::IDENTITY)
.build()
.unwrap();
let err = tree.lookup("map", "base_lnik", stamp());
let err = err.unwrap_err();
assert!(matches!(err, LookupError::UnknownFrame { .. }), "{err:?}");
let msg = tree.describe(err).to_string();
for name in ["map", "odom", "base_link"] {
assert!(
msg.contains(name),
"the description names no frame the tree actually has: {msg}"
);
}
assert!(
msg.contains("await_frames"),
"the description offers no remedy: {msg}"
);
assert!(
!msg.contains("tf_treed"),
"the remedy names a program that does not exist: {msg}"
);
}
#[test]
fn the_described_frame_listing_is_bounded_and_sorted() {
let mut b = TreeBuilder::new();
for i in 0..12 {
b = b.dynamic_edge(
"hub",
&format!("frame_{i:02}"),
EdgeCfg::new(Capacity::slots(4)),
);
}
let tree = b.build().unwrap();
let err = tree.lookup("hub", "not_here", stamp()).unwrap_err();
let msg = tree.describe(err).to_string();
assert!(
msg.contains("frame_00") && msg.contains("frame_07"),
"the first eight sorted names should be listed: {msg}"
);
assert!(!msg.contains("frame_11"), "the listing is unbounded: {msg}");
assert!(
msg.contains("13 total"),
"a truncated listing must say how many there were: {msg}"
);
}
#[test]
fn an_empty_tree_says_it_is_empty_rather_than_listing_nothing() {
let tree = TreeBuilder::new().build().unwrap();
assert!(tree.frames().unwrap().is_empty());
let err = tree.lookup("map", "odom", stamp()).unwrap_err();
let msg = tree.describe(err).to_string();
assert!(
msg.contains("no frames yet"),
"an empty tree should say so: {msg}"
);
assert!(
msg.contains("await_frames"),
"the description offers no remedy: {msg}"
);
}