use bytes::Bytes;
use unb_core::{ApplicationHead, Envelope, TargetPath};
#[test]
fn target_path_separates_final_node_from_local_subject() {
let path = TargetPath::parse_application("/node-a/weather/current").unwrap();
assert_eq!(path.target(), "node-a");
assert_eq!(path.subject(), "weather.current");
assert_eq!(path.to_string(), "/node-a/weather/current");
}
#[test]
fn discovery_path_contains_only_the_final_node() {
let path = TargetPath::parse_discovery("/node.a").unwrap();
assert_eq!(path.target(), "node.a");
assert_eq!(path.subject(), "");
assert_eq!(path.to_string(), "/node.a");
}
#[test]
fn malformed_target_paths_are_rejected_before_routing() {
for invalid in [
"weather/current",
"/weather",
"//weather",
"/node-a/",
"/node-a/weather//current",
"/node-a/weather?unit=c",
"/node-a/weather#current",
"/node-a/we\nather",
"/node a/weather",
"/nøde/weather",
"/n%20ode/weather",
"/az/weather",
"/node-a/weather..current",
] {
assert!(
TargetPath::parse_application(invalid).is_err(),
"accepted malformed application path {invalid:?}"
);
}
for invalid in [
"node-a",
"/",
"/node-a/weather",
"/node-a?detail=full",
"/node-a#catalog",
"/node\na",
"/node a",
"/nøde",
"/n%20ode",
"/az",
] {
assert!(
TargetPath::parse_discovery(invalid).is_err(),
"accepted malformed discovery path {invalid:?}"
);
}
}
#[test]
fn semantic_parts_format_as_one_canonical_slash_path() {
let application = TargetPath::application("node-a", "weather.current").unwrap();
let discovery = TargetPath::discovery("node-a").unwrap();
assert_eq!(application.to_string(), "/node-a/weather/current");
assert_eq!(discovery.to_string(), "/node-a");
assert!(TargetPath::application("node-a", "weather..current").is_err());
assert!(TargetPath::discovery("node/a").is_err());
}
#[test]
fn application_heads_carry_target_and_local_subject_separately() {
let request = http::Request::post("/node-a/weather/current")
.body(Bytes::new())
.unwrap();
let envelope = Envelope::from_request(request).unwrap();
assert_eq!(envelope.target, "node-a");
assert_eq!(envelope.subject, "weather.current");
let head = ApplicationHead::from_envelope(&envelope).unwrap();
assert_eq!(head.target, "node-a");
assert_eq!(head.subject, "weather.current");
let projected = head.into_envelope();
assert_eq!(projected.target, "node-a");
assert_eq!(projected.subject, "weather.current");
}
#[test]
fn terminal_request_projection_hides_the_target_prefix() {
let request = http::Request::post("/node-a/weather/current")
.body(Bytes::new())
.unwrap();
let envelope = Envelope::from_request(request).unwrap();
let local = envelope.to_local_request().unwrap();
assert_eq!(local.uri().path(), "/weather/current");
}