google_cloud_gax/error/
binding.rs1#[derive(thiserror::Error, Debug, PartialEq)]
33pub struct BindingError {
34 pub paths: Vec<PathMismatch>,
37}
38
39#[derive(Debug, Default, PartialEq)]
46pub struct PathMismatch {
47 pub subs: Vec<SubstitutionMismatch>,
49}
50
51#[derive(Debug, PartialEq)]
55pub enum SubstitutionFail {
56 Unset,
58 UnsetExpecting(&'static str),
60 MismatchExpecting(String, &'static str),
67}
68
69#[derive(Debug, PartialEq)]
73pub struct SubstitutionMismatch {
74 pub field_name: &'static str,
78 pub problem: SubstitutionFail,
80}
81
82impl std::fmt::Display for SubstitutionMismatch {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 match &self.problem {
85 SubstitutionFail::Unset => {
86 write!(f, "field `{}` needs to be set.", self.field_name)
87 }
88 SubstitutionFail::UnsetExpecting(expected) => {
89 write!(
90 f,
91 "field `{}` needs to be set and match the template: '{}'",
92 self.field_name, expected
93 )
94 }
95 SubstitutionFail::MismatchExpecting(actual, expected) => {
96 write!(
97 f,
98 "field `{}` should match the template: '{}'; found: '{}'",
99 self.field_name, expected, actual
100 )
101 }
102 }
103 }
104}
105
106impl std::fmt::Display for PathMismatch {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 for (i, sub) in self.subs.iter().enumerate() {
109 if i != 0 {
110 write!(f, " AND ")?;
111 }
112 write!(f, "{sub}")?;
113 }
114 Ok(())
115 }
116}
117
118impl std::fmt::Display for BindingError {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 write!(f, "at least one of the conditions must be met: ")?;
121 for (i, sub) in self.paths.iter().enumerate() {
122 if i != 0 {
123 write!(f, " OR ")?;
124 }
125 write!(f, "({}) {}", i + 1, sub)?;
126 }
127 Ok(())
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn fmt_path_mismatch() {
137 let pm = PathMismatch {
138 subs: vec![
139 SubstitutionMismatch {
140 field_name: "parent",
141 problem: SubstitutionFail::MismatchExpecting(
142 "project-id-only".to_string(),
143 "projects/*",
144 ),
145 },
146 SubstitutionMismatch {
147 field_name: "location",
148 problem: SubstitutionFail::UnsetExpecting("locations/*"),
149 },
150 SubstitutionMismatch {
151 field_name: "id",
152 problem: SubstitutionFail::Unset,
153 },
154 ],
155 };
156
157 let fmt = format!("{pm}");
158 let clauses: Vec<&str> = fmt.split(" AND ").collect();
159 assert!(clauses.len() == 3, "{fmt}");
160 let c0 = clauses[0];
161 assert!(
162 c0.contains("parent")
163 && !c0.contains("needs to be set")
164 && c0.contains("should match")
165 && c0.contains("projects/*")
166 && c0.contains("found")
167 && c0.contains("project-id-only"),
168 "{c0}"
169 );
170 let c1 = clauses[1];
171 assert!(
172 c1.contains("location")
173 && c1.contains("needs to be set")
174 && c1.contains("locations/*")
175 && !c1.contains("found"),
176 "{c1}"
177 );
178 let c2 = clauses[2];
179 assert!(
180 c2.contains("id") && c2.contains("needs to be set") && !c2.contains("found"),
181 "{c2}"
182 );
183 }
184
185 #[test]
186 fn fmt_binding_error() {
187 let e = BindingError {
188 paths: vec![
189 PathMismatch {
190 subs: vec![SubstitutionMismatch {
191 field_name: "parent",
192 problem: SubstitutionFail::MismatchExpecting(
193 "project-id-only".to_string(),
194 "projects/*",
195 ),
196 }],
197 },
198 PathMismatch {
199 subs: vec![SubstitutionMismatch {
200 field_name: "location",
201 problem: SubstitutionFail::UnsetExpecting("locations/*"),
202 }],
203 },
204 PathMismatch {
205 subs: vec![SubstitutionMismatch {
206 field_name: "id",
207 problem: SubstitutionFail::Unset,
208 }],
209 },
210 ],
211 };
212 let fmt = format!("{e}");
213 assert!(fmt.contains("one of the conditions must be met"), "{fmt}");
214 let clauses: Vec<&str> = fmt.split(" OR ").collect();
215 assert!(clauses.len() == 3, "{fmt}");
216 let c0 = clauses[0];
217 assert!(
218 c0.contains("(1)")
219 && c0.contains("parent")
220 && c0.contains("should match")
221 && c0.contains("projects/*")
222 && c0.contains("project-id-only"),
223 "{c0}"
224 );
225 let c1 = clauses[1];
226 assert!(
227 c1.contains("(2)") && c1.contains("location") && c1.contains("locations/*"),
228 "{c1}"
229 );
230 let c2 = clauses[2];
231 assert!(
232 c2.contains("(3)") && c2.contains("id") && c2.contains("needs to be set"),
233 "{c2}"
234 );
235 }
236}