twiml_rust/
validation_warnings.rs1use crate::messaging::{MessagingResponse, MessagingVerb};
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum TwiMLWarning {
10 UnreachableRedirectAfterMessageWithAction {
13 message_index: usize,
14 redirect_index: usize,
15 },
16
17 EmptyRedirectUrl { redirect_index: usize },
19
20 UnreachableVerbsAfterRedirect {
22 redirect_index: usize,
23 unreachable_count: usize,
24 },
25}
26
27impl std::fmt::Display for TwiMLWarning {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 TwiMLWarning::UnreachableRedirectAfterMessageWithAction {
31 message_index,
32 redirect_index,
33 } => {
34 write!(
35 f,
36 "Warning: Redirect at index {} may be unreachable because Message at index {} has an action attribute",
37 redirect_index, message_index
38 )
39 }
40 TwiMLWarning::EmptyRedirectUrl { redirect_index } => {
41 write!(
42 f,
43 "Warning: Redirect at index {} has an empty URL, which will create an infinite loop",
44 redirect_index
45 )
46 }
47 TwiMLWarning::UnreachableVerbsAfterRedirect {
48 redirect_index,
49 unreachable_count,
50 } => {
51 write!(
52 f,
53 "Warning: {} verb(s) after Redirect at index {} will never be reached",
54 unreachable_count, redirect_index
55 )
56 }
57 }
58 }
59}
60
61impl MessagingResponse {
62 pub fn validate(&self) -> Vec<TwiMLWarning> {
79 let mut warnings = Vec::new();
80
81 for (i, verb) in self.verbs.iter().enumerate() {
83 if matches!(verb, MessagingVerb::Redirect(_)) {
84 let remaining = self.verbs.len() - i - 1;
85 if remaining > 0 {
86 warnings.push(TwiMLWarning::UnreachableVerbsAfterRedirect {
87 redirect_index: i,
88 unreachable_count: remaining,
89 });
90 }
91 }
92 }
93
94 warnings
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::messaging::MessagingResponse;
102
103 #[test]
104 fn test_no_warnings_for_simple_message() {
105 let response = MessagingResponse::new().message("Hello!");
106 let warnings = response.validate();
107 assert!(warnings.is_empty());
108 }
109
110 #[test]
111 fn test_no_warnings_for_message_then_redirect() {
112 let response = MessagingResponse::new()
113 .message("Hello!")
114 .redirect("https://example.com");
115 let warnings = response.validate();
116 assert!(warnings.is_empty());
117 }
118
119 #[test]
120 fn test_warning_for_verbs_after_redirect() {
121 let response = MessagingResponse::new()
122 .redirect("https://example.com")
123 .message("This will never be sent");
124
125 let warnings = response.validate();
126 assert_eq!(warnings.len(), 1);
127 assert!(matches!(
128 warnings[0],
129 TwiMLWarning::UnreachableVerbsAfterRedirect {
130 redirect_index: 0,
131 unreachable_count: 1
132 }
133 ));
134 }
135
136 #[test]
137 fn test_warning_display() {
138 let warning = TwiMLWarning::UnreachableVerbsAfterRedirect {
139 redirect_index: 0,
140 unreachable_count: 2,
141 };
142 let display = format!("{}", warning);
143 assert!(display.contains("2 verb(s)"));
144 assert!(display.contains("index 0"));
145 }
146}