zerodds_soap/
addressing.rs1use alloc::format;
10use alloc::string::String;
11
12pub const WSA_NS: &str = "http://www.w3.org/2005/08/addressing";
14
15#[derive(Debug, Clone, PartialEq, Eq, Default)]
17pub struct AddressingHeaders {
18 pub to: Option<String>,
20 pub action: Option<String>,
22 pub message_id: Option<String>,
24 pub relates_to: Option<String>,
27 pub from: Option<String>,
29 pub reply_to: Option<String>,
32 pub fault_to: Option<String>,
34}
35
36#[must_use]
39pub fn build_addressing_header(h: &AddressingHeaders) -> String {
40 let mut out = String::new();
41 if let Some(to) = &h.to {
42 out.push_str(&format!("<wsa:To xmlns:wsa=\"{WSA_NS}\">{to}</wsa:To>"));
43 }
44 if let Some(action) = &h.action {
45 out.push_str(&format!(
46 "<wsa:Action xmlns:wsa=\"{WSA_NS}\">{action}</wsa:Action>"
47 ));
48 }
49 if let Some(mid) = &h.message_id {
50 out.push_str(&format!(
51 "<wsa:MessageID xmlns:wsa=\"{WSA_NS}\">{mid}</wsa:MessageID>"
52 ));
53 }
54 if let Some(r) = &h.relates_to {
55 out.push_str(&format!(
56 "<wsa:RelatesTo xmlns:wsa=\"{WSA_NS}\">{r}</wsa:RelatesTo>"
57 ));
58 }
59 if let Some(f) = &h.from {
60 out.push_str(&format!(
61 "<wsa:From xmlns:wsa=\"{WSA_NS}\"><wsa:Address>{f}</wsa:Address></wsa:From>"
62 ));
63 }
64 if let Some(r) = &h.reply_to {
65 out.push_str(&format!(
66 "<wsa:ReplyTo xmlns:wsa=\"{WSA_NS}\"><wsa:Address>{r}</wsa:Address></wsa:ReplyTo>"
67 ));
68 }
69 if let Some(f) = &h.fault_to {
70 out.push_str(&format!(
71 "<wsa:FaultTo xmlns:wsa=\"{WSA_NS}\"><wsa:Address>{f}</wsa:Address></wsa:FaultTo>"
72 ));
73 }
74 out
75}
76
77#[cfg(test)]
78#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn empty_headers_produce_empty_string() {
84 let h = AddressingHeaders::default();
85 assert!(build_addressing_header(&h).is_empty());
86 }
87
88 #[test]
89 fn to_and_action_are_emitted() {
90 let h = AddressingHeaders {
91 to: Some("http://server/ep".into()),
92 action: Some("http://demo/Action/Echo".into()),
93 ..AddressingHeaders::default()
94 };
95 let out = build_addressing_header(&h);
96 assert!(out.contains("<wsa:To"));
97 assert!(out.contains("http://server/ep"));
98 assert!(out.contains("<wsa:Action"));
99 assert!(out.contains("http://demo/Action/Echo"));
100 }
101
102 #[test]
103 fn message_id_and_relates_to_round_trip() {
104 let h = AddressingHeaders {
105 message_id: Some("uuid:1".into()),
106 relates_to: Some("uuid:0".into()),
107 ..AddressingHeaders::default()
108 };
109 let out = build_addressing_header(&h);
110 assert!(out.contains("uuid:1"));
111 assert!(out.contains("uuid:0"));
112 }
113
114 #[test]
115 fn reply_to_and_fault_to_emit_address_subelement() {
116 let h = AddressingHeaders {
117 reply_to: Some("http://client/reply".into()),
118 fault_to: Some("http://client/fault".into()),
119 ..AddressingHeaders::default()
120 };
121 let out = build_addressing_header(&h);
122 assert!(out.contains("<wsa:ReplyTo"));
123 assert!(out.contains("<wsa:Address>http://client/reply</wsa:Address>"));
124 assert!(out.contains("<wsa:FaultTo"));
125 assert!(out.contains("<wsa:Address>http://client/fault</wsa:Address>"));
126 }
127
128 #[test]
129 fn ns_constant_is_w3c_2005_08() {
130 assert_eq!(WSA_NS, "http://www.w3.org/2005/08/addressing");
131 }
132}