1use {
2 super::{
3 arn::{arn_match, ArnCmp},
4 binary::{binary_match, BINARY_DISPLAY_NAMES},
5 boolean::{bool_match, BOOL_DISPLAY_NAMES},
6 date::{date_match, DateCmp},
7 ipaddr::{ip_address_match, IP_ADDRESS_DISPLAY_NAMES},
8 null::{null_match, NULL_DISPLAY_NAME},
9 numeric::{numeric_match, NumericCmp},
10 string::{string_match, StringCmp},
11 variant::Variant,
12 },
13 crate::{serutil::StringLikeList, AspenError, Context, PolicyVersion},
14 scratchstack_aws_principal::SessionValue,
15 serde::{de, de::Deserializer, ser::Serializer, Deserialize, Serialize},
16 std::{
17 borrow::Borrow,
18 collections::BTreeMap,
19 fmt::{Debug, Display, Formatter, Result as FmtResult},
20 str::FromStr,
21 },
22};
23
24#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
26pub enum ConditionOp {
27 Arn(ArnCmp, Variant),
29
30 Binary(Variant),
32
33 Bool(Variant),
35
36 Date(DateCmp, Variant),
38
39 IpAddress(Variant),
41
42 Null,
44
45 Numeric(NumericCmp, Variant),
47
48 String(StringCmp, Variant),
50}
51
52pub const ArnEquals: ConditionOp = ConditionOp::Arn(ArnCmp::Equals, Variant::None);
54
55pub const ArnEqualsIfExists: ConditionOp = ConditionOp::Arn(ArnCmp::Equals, Variant::IfExists);
57
58pub const ArnNotEquals: ConditionOp = ConditionOp::Arn(ArnCmp::Equals, Variant::Negated);
60
61pub const ArnNotEqualsIfExists: ConditionOp = ConditionOp::Arn(ArnCmp::Equals, Variant::IfExistsNegated);
63
64pub const ArnLike: ConditionOp = ConditionOp::Arn(ArnCmp::Like, Variant::None);
66
67pub const ArnLikeIfExists: ConditionOp = ConditionOp::Arn(ArnCmp::Like, Variant::IfExists);
69
70pub const ArnNotLike: ConditionOp = ConditionOp::Arn(ArnCmp::Like, Variant::Negated);
72
73pub const ArnNotLikeIfExists: ConditionOp = ConditionOp::Arn(ArnCmp::Like, Variant::IfExistsNegated);
75
76pub const BinaryEquals: ConditionOp = ConditionOp::Binary(Variant::None);
78
79pub const BinaryEqualsIfExists: ConditionOp = ConditionOp::Binary(Variant::IfExists);
81
82pub const Bool: ConditionOp = ConditionOp::Bool(Variant::None);
84
85pub const BoolIfExists: ConditionOp = ConditionOp::Bool(Variant::IfExists);
87
88pub const DateEquals: ConditionOp = ConditionOp::Date(DateCmp::Equals, Variant::None);
90
91pub const DateEqualsIfExists: ConditionOp = ConditionOp::Date(DateCmp::Equals, Variant::IfExists);
93
94pub const DateNotEquals: ConditionOp = ConditionOp::Date(DateCmp::Equals, Variant::Negated);
96
97pub const DateNotEqualsIfExists: ConditionOp = ConditionOp::Date(DateCmp::Equals, Variant::IfExistsNegated);
99
100pub const DateLessThan: ConditionOp = ConditionOp::Date(DateCmp::LessThan, Variant::None);
102
103pub const DateLessThanIfExists: ConditionOp = ConditionOp::Date(DateCmp::LessThan, Variant::IfExists);
105
106pub const DateGreaterThanEquals: ConditionOp = ConditionOp::Date(DateCmp::LessThan, Variant::Negated);
108
109pub const DateGreaterThanEqualsIfExists: ConditionOp = ConditionOp::Date(DateCmp::LessThan, Variant::IfExistsNegated);
111
112pub const DateLessThanEquals: ConditionOp = ConditionOp::Date(DateCmp::LessThanEquals, Variant::None);
114
115pub const DateLessThanEqualsIfExists: ConditionOp = ConditionOp::Date(DateCmp::LessThanEquals, Variant::IfExists);
117
118pub const DateGreaterThan: ConditionOp = ConditionOp::Date(DateCmp::LessThanEquals, Variant::Negated);
120
121pub const DateGreaterThanIfExists: ConditionOp = ConditionOp::Date(DateCmp::LessThanEquals, Variant::IfExistsNegated);
123
124pub const IpAddress: ConditionOp = ConditionOp::IpAddress(Variant::None);
126
127pub const IpAddressIfExists: ConditionOp = ConditionOp::IpAddress(Variant::IfExists);
129
130pub const NotIpAddress: ConditionOp = ConditionOp::IpAddress(Variant::Negated);
132
133pub const NotIpAddressIfExists: ConditionOp = ConditionOp::IpAddress(Variant::IfExistsNegated);
135
136pub const Null: ConditionOp = ConditionOp::Null;
138
139pub const NumericEquals: ConditionOp = ConditionOp::Numeric(NumericCmp::Equals, Variant::None);
141
142pub const NumericEqualsIfExists: ConditionOp = ConditionOp::Numeric(NumericCmp::Equals, Variant::IfExists);
144
145pub const NumericNotEquals: ConditionOp = ConditionOp::Numeric(NumericCmp::Equals, Variant::Negated);
147
148pub const NumericNotEqualsIfExists: ConditionOp = ConditionOp::Numeric(NumericCmp::Equals, Variant::IfExistsNegated);
150
151pub const NumericLessThan: ConditionOp = ConditionOp::Numeric(NumericCmp::LessThan, Variant::None);
153
154pub const NumericLessThanIfExists: ConditionOp = ConditionOp::Numeric(NumericCmp::LessThan, Variant::IfExists);
156
157pub const NumericGreaterThanEquals: ConditionOp = ConditionOp::Numeric(NumericCmp::LessThan, Variant::Negated);
159
160pub const NumericGreaterThanEqualsIfExists: ConditionOp =
162 ConditionOp::Numeric(NumericCmp::LessThan, Variant::IfExistsNegated);
163
164pub const NumericLessThanEquals: ConditionOp = ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::None);
166
167pub const NumericLessThanEqualsIfExists: ConditionOp =
169 ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::IfExists);
170
171pub const NumericGreaterThan: ConditionOp = ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::Negated);
173
174pub const NumericGreaterThanIfExists: ConditionOp =
176 ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::IfExistsNegated);
177
178pub const StringEquals: ConditionOp = ConditionOp::String(StringCmp::Equals, Variant::None);
180
181pub const StringEqualsIfExists: ConditionOp = ConditionOp::String(StringCmp::Equals, Variant::IfExists);
183
184pub const StringNotEquals: ConditionOp = ConditionOp::String(StringCmp::Equals, Variant::Negated);
186
187pub const StringNotEqualsIfExists: ConditionOp = ConditionOp::String(StringCmp::Equals, Variant::IfExistsNegated);
189
190pub const StringEqualsIgnoreCase: ConditionOp = ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::None);
192
193pub const StringEqualsIgnoreCaseIfExists: ConditionOp =
195 ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::IfExists);
196
197pub const StringNotEqualsIgnoreCase: ConditionOp = ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::Negated);
199
200pub const StringNotEqualsIgnoreCaseIfExists: ConditionOp =
202 ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::IfExistsNegated);
203
204pub const StringLike: ConditionOp = ConditionOp::String(StringCmp::Like, Variant::None);
206
207pub const StringLikeIfExists: ConditionOp = ConditionOp::String(StringCmp::Like, Variant::IfExists);
209
210pub const StringNotLike: ConditionOp = ConditionOp::String(StringCmp::Like, Variant::Negated);
212
213pub const StringNotLikeIfExists: ConditionOp = ConditionOp::String(StringCmp::Like, Variant::IfExistsNegated);
215
216impl Borrow<str> for ConditionOp {
217 fn borrow(&self) -> &str {
218 match self {
219 Self::Arn(cmp, variant) => cmp.display_name(variant),
220 Self::Binary(variant) => BINARY_DISPLAY_NAMES[variant.as_usize()],
221 Self::Bool(variant) => BOOL_DISPLAY_NAMES[variant.as_usize()],
222 Self::Date(cmp, variant) => cmp.display_name(variant),
223 Self::IpAddress(variant) => IP_ADDRESS_DISPLAY_NAMES[variant.as_usize()],
224 Self::Null => NULL_DISPLAY_NAME,
225 Self::Numeric(cmp, variant) => cmp.display_name(variant),
226 Self::String(cmp, variant) => cmp.display_name(variant),
227 }
228 }
229}
230
231impl PartialEq<str> for ConditionOp {
232 fn eq(&self, other: &str) -> bool {
233 self.to_string().as_str() == other
234 }
235}
236
237impl Display for ConditionOp {
238 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
239 f.write_str(self.borrow())
240 }
241}
242
243impl<'de> Deserialize<'de> for ConditionOp {
244 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
245 let s = String::deserialize(deserializer)?;
246 ConditionOp::from_str(&s).map_err(de::Error::custom)
247 }
248}
249
250impl Serialize for ConditionOp {
251 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
252 serializer.serialize_str(&self.to_string())
253 }
254}
255
256const NULL: SessionValue = SessionValue::Null;
257
258impl ConditionOp {
259 pub fn matches(
268 &self,
269 condition: &BTreeMap<String, StringLikeList<String>>,
270 context: &Context,
271 pv: PolicyVersion,
272 ) -> Result<bool, AspenError> {
273 for (key, allowed) in condition.iter() {
274 let value = context.session_data().get(key).unwrap_or(&NULL);
275
276 let result = match self {
277 Self::Arn(cmp, variant) => arn_match(context, pv, allowed, value, *cmp, *variant),
278 Self::Binary(variant) => binary_match(context, pv, allowed, value, *variant),
279 Self::Bool(variant) => bool_match(context, pv, allowed, value, *variant),
280 Self::Date(cmp, variant) => date_match(context, pv, allowed, value, *cmp, *variant),
281 Self::IpAddress(variant) => ip_address_match(context, pv, allowed, value, *variant),
282 Self::Null => null_match(context, pv, allowed, value),
283 Self::Numeric(cmp, variant) => numeric_match(context, pv, allowed, value, *cmp, *variant),
284 Self::String(cmp, variant) => string_match(context, pv, allowed, value, *cmp, *variant),
285 }?;
286
287 if !result {
288 return Ok(false);
289 }
290 }
291
292 Ok(true)
293 }
294}
295
296impl FromStr for ConditionOp {
297 type Err = AspenError;
298
299 fn from_str(s: &str) -> Result<Self, Self::Err> {
300 match s {
301 "ArnEquals" => Ok(ArnEquals),
302 "ArnEqualsIfExists" => Ok(ArnEqualsIfExists),
303 "ArnNotEquals" => Ok(ArnNotEquals),
304 "ArnNotEqualsIfExists" => Ok(ArnNotEqualsIfExists),
305 "ArnLike" => Ok(ArnLike),
306 "ArnLikeIfExists" => Ok(ArnLikeIfExists),
307 "ArnNotLike" => Ok(ArnNotLike),
308 "ArnNotLikeIfExists" => Ok(ArnNotLikeIfExists),
309 "BinaryEquals" => Ok(BinaryEquals),
310 "BinaryEqualsIfExists" => Ok(BinaryEqualsIfExists),
311 "Bool" => Ok(Bool),
312 "BoolIfExists" => Ok(BoolIfExists),
313 "DateEquals" => Ok(DateEquals),
314 "DateEqualsIfExists" => Ok(DateEqualsIfExists),
315 "DateNotEquals" => Ok(DateNotEquals),
316 "DateNotEqualsIfExists" => Ok(DateNotEqualsIfExists),
317 "DateLessThan" => Ok(DateLessThan),
318 "DateLessThanIfExists" => Ok(DateLessThanIfExists),
319 "DateGreaterThanEquals" => Ok(DateGreaterThanEquals),
320 "DateGreaterThanEqualsIfExists" => Ok(DateGreaterThanEqualsIfExists),
321 "DateLessThanEquals" => Ok(DateLessThanEquals),
322 "DateLessThanEqualsIfExists" => Ok(DateLessThanEqualsIfExists),
323 "DateGreaterThan" => Ok(DateGreaterThan),
324 "DateGreaterThanIfExists" => Ok(DateGreaterThanIfExists),
325 "IpAddress" => Ok(IpAddress),
326 "IpAddressIfExists" => Ok(IpAddressIfExists),
327 "NotIpAddress" => Ok(NotIpAddress),
328 "NotIpAddressIfExists" => Ok(NotIpAddressIfExists),
329 "Null" => Ok(Null),
330 "NumericEquals" => Ok(NumericEquals),
331 "NumericEqualsIfExists" => Ok(NumericEqualsIfExists),
332 "NumericNotEquals" => Ok(NumericNotEquals),
333 "NumericNotEqualsIfExists" => Ok(NumericNotEqualsIfExists),
334 "NumericLessThan" => Ok(NumericLessThan),
335 "NumericLessThanIfExists" => Ok(NumericLessThanIfExists),
336 "NumericGreaterThanEquals" => Ok(NumericGreaterThanEquals),
337 "NumericGreaterThanEqualsIfExists" => Ok(NumericGreaterThanEqualsIfExists),
338 "NumericLessThanEquals" => Ok(NumericLessThanEquals),
339 "NumericLessThanEqualsIfExists" => Ok(NumericLessThanEqualsIfExists),
340 "NumericGreaterThan" => Ok(NumericGreaterThan),
341 "NumericGreaterThanIfExists" => Ok(NumericGreaterThanIfExists),
342 "StringEquals" => Ok(StringEquals),
343 "StringEqualsIfExists" => Ok(StringEqualsIfExists),
344 "StringNotEquals" => Ok(StringNotEquals),
345 "StringNotEqualsIfExists" => Ok(StringNotEqualsIfExists),
346 "StringEqualsIgnoreCase" => Ok(StringEqualsIgnoreCase),
347 "StringEqualsIgnoreCaseIfExists" => Ok(StringEqualsIgnoreCaseIfExists),
348 "StringNotEqualsIgnoreCase" => Ok(StringNotEqualsIgnoreCase),
349 "StringNotEqualsIgnoreCaseIfExists" => Ok(StringNotEqualsIgnoreCaseIfExists),
350 "StringLike" => Ok(StringLike),
351 "StringLikeIfExists" => Ok(StringLikeIfExists),
352 "StringNotLike" => Ok(StringNotLike),
353 "StringNotLikeIfExists" => Ok(StringNotLikeIfExists),
354 _ => Err(AspenError::InvalidConditionOperator(s.to_string())),
355 }
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use {
362 crate::{
363 condition::{
364 arn::ArnCmp, date::DateCmp, numeric::NumericCmp, op::ConditionOp, string::StringCmp, variant::Variant,
365 },
366 condop,
367 },
368 std::{
369 cmp::{Ordering, PartialOrd},
370 collections::hash_map::DefaultHasher,
371 hash::{Hash, Hasher},
372 str::FromStr,
373 },
374 };
375
376 #[test_log::test]
377 fn test_derived() {
378 let cops = vec![
379 (ConditionOp::Arn(ArnCmp::Equals, Variant::None), "Arn(Equals, None)"),
380 (ConditionOp::Arn(ArnCmp::Equals, Variant::IfExists), "Arn(Equals, IfExists)"),
381 (ConditionOp::Arn(ArnCmp::Equals, Variant::Negated), "Arn(Equals, Negated)"),
382 (ConditionOp::Arn(ArnCmp::Equals, Variant::IfExistsNegated), "Arn(Equals, IfExistsNegated)"),
383 (ConditionOp::Arn(ArnCmp::Like, Variant::None), "Arn(Like, None)"),
384 (ConditionOp::Arn(ArnCmp::Like, Variant::IfExists), "Arn(Like, IfExists)"),
385 (ConditionOp::Arn(ArnCmp::Like, Variant::Negated), "Arn(Like, Negated)"),
386 (ConditionOp::Arn(ArnCmp::Like, Variant::IfExistsNegated), "Arn(Like, IfExistsNegated)"),
387 (ConditionOp::Binary(Variant::None), "Binary(None)"),
388 (ConditionOp::Binary(Variant::IfExists), "Binary(IfExists)"),
389 (ConditionOp::Bool(Variant::None), "Bool(None)"),
390 (ConditionOp::Bool(Variant::IfExists), "Bool(IfExists)"),
391 (ConditionOp::Date(DateCmp::Equals, Variant::None), "Date(Equals, None)"),
392 (ConditionOp::Date(DateCmp::Equals, Variant::IfExists), "Date(Equals, IfExists)"),
393 (ConditionOp::Date(DateCmp::Equals, Variant::Negated), "Date(Equals, Negated)"),
394 (ConditionOp::Date(DateCmp::Equals, Variant::IfExistsNegated), "Date(Equals, IfExistsNegated)"),
395 (ConditionOp::Date(DateCmp::LessThan, Variant::None), "Date(LessThan, None)"),
396 (ConditionOp::Date(DateCmp::LessThan, Variant::IfExists), "Date(LessThan, IfExists)"),
397 (ConditionOp::Date(DateCmp::LessThan, Variant::Negated), "Date(LessThan, Negated)"),
398 (ConditionOp::Date(DateCmp::LessThan, Variant::IfExistsNegated), "Date(LessThan, IfExistsNegated)"),
399 (ConditionOp::Date(DateCmp::LessThanEquals, Variant::None), "Date(LessThanEquals, None)"),
400 (ConditionOp::Date(DateCmp::LessThanEquals, Variant::IfExists), "Date(LessThanEquals, IfExists)"),
401 (ConditionOp::Date(DateCmp::LessThanEquals, Variant::Negated), "Date(LessThanEquals, Negated)"),
402 (
403 ConditionOp::Date(DateCmp::LessThanEquals, Variant::IfExistsNegated),
404 "Date(LessThanEquals, IfExistsNegated)",
405 ),
406 (ConditionOp::IpAddress(Variant::None), "IpAddress(None)"),
407 (ConditionOp::IpAddress(Variant::IfExists), "IpAddress(IfExists)"),
408 (ConditionOp::IpAddress(Variant::Negated), "IpAddress(Negated)"),
409 (ConditionOp::IpAddress(Variant::IfExistsNegated), "IpAddress(IfExistsNegated)"),
410 (ConditionOp::Null, "Null"),
411 (ConditionOp::Numeric(NumericCmp::Equals, Variant::None), "Numeric(Equals, None)"),
412 (ConditionOp::Numeric(NumericCmp::Equals, Variant::IfExists), "Numeric(Equals, IfExists)"),
413 (ConditionOp::Numeric(NumericCmp::Equals, Variant::Negated), "Numeric(Equals, Negated)"),
414 (ConditionOp::Numeric(NumericCmp::Equals, Variant::IfExistsNegated), "Numeric(Equals, IfExistsNegated)"),
415 (ConditionOp::Numeric(NumericCmp::LessThan, Variant::None), "Numeric(LessThan, None)"),
416 (ConditionOp::Numeric(NumericCmp::LessThan, Variant::IfExists), "Numeric(LessThan, IfExists)"),
417 (ConditionOp::Numeric(NumericCmp::LessThan, Variant::Negated), "Numeric(LessThan, Negated)"),
418 (
419 ConditionOp::Numeric(NumericCmp::LessThan, Variant::IfExistsNegated),
420 "Numeric(LessThan, IfExistsNegated)",
421 ),
422 (ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::None), "Numeric(LessThanEquals, None)"),
423 (ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::IfExists), "Numeric(LessThanEquals, IfExists)"),
424 (ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::Negated), "Numeric(LessThanEquals, Negated)"),
425 (
426 ConditionOp::Numeric(NumericCmp::LessThanEquals, Variant::IfExistsNegated),
427 "Numeric(LessThanEquals, IfExistsNegated)",
428 ),
429 (ConditionOp::String(StringCmp::Equals, Variant::None), "String(Equals, None)"),
430 (ConditionOp::String(StringCmp::Equals, Variant::IfExists), "String(Equals, IfExists)"),
431 (ConditionOp::String(StringCmp::Equals, Variant::Negated), "String(Equals, Negated)"),
432 (ConditionOp::String(StringCmp::Equals, Variant::IfExistsNegated), "String(Equals, IfExistsNegated)"),
433 (ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::None), "String(EqualsIgnoreCase, None)"),
434 (ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::IfExists), "String(EqualsIgnoreCase, IfExists)"),
435 (ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::Negated), "String(EqualsIgnoreCase, Negated)"),
436 (
437 ConditionOp::String(StringCmp::EqualsIgnoreCase, Variant::IfExistsNegated),
438 "String(EqualsIgnoreCase, IfExistsNegated)",
439 ),
440 (ConditionOp::String(StringCmp::Like, Variant::None), "String(Like, None)"),
441 (ConditionOp::String(StringCmp::Like, Variant::IfExists), "String(Like, IfExists)"),
442 (ConditionOp::String(StringCmp::Like, Variant::Negated), "String(Like, Negated)"),
443 (ConditionOp::String(StringCmp::Like, Variant::IfExistsNegated), "String(Like, IfExistsNegated)"),
444 ];
445
446 for (cop, debug) in &cops {
447 assert_eq!(&format!("{cop:?}"), debug);
448 }
449
450 for i in 0..cops.len() {
451 let mut hasher = DefaultHasher::new();
452 cops[i].0.hash(&mut hasher);
453 let i_hash = hasher.finish();
454
455 for j in 0..cops.len() {
456 let mut hasher = DefaultHasher::new();
457 cops[j].0.hash(&mut hasher);
458 let j_hash = hasher.finish();
459
460 match i.cmp(&j) {
461 Ordering::Equal => {
462 assert_eq!(cops[i].0, cops[j].0);
463 assert_eq!(i_hash, j_hash);
464 assert_eq!(cops[i].0.cmp(&cops[j].0), Ordering::Equal);
465 assert_eq!(cops[i].0.partial_cmp(&cops[j].0), Some(Ordering::Equal));
466 }
467 Ordering::Less => {
468 assert_ne!(cops[i].0, cops[j].0);
469 assert_ne!(i_hash, j_hash);
470 assert_eq!(cops[i].0.cmp(&cops[j].0), Ordering::Less);
471 assert_eq!(cops[i].0.partial_cmp(&cops[j].0), Some(Ordering::Less));
472 }
473 Ordering::Greater => {
474 assert_ne!(cops[i].0, cops[j].0);
475 assert_ne!(i_hash, j_hash);
476 assert_eq!(cops[i].0.cmp(&cops[j].0), Ordering::Greater);
477 assert_eq!(cops[i].0.partial_cmp(&cops[j].0), Some(Ordering::Greater));
478 }
479 }
480 }
481 }
482 }
483
484 #[test_log::test]
485 fn test_deserialize_bad_type() {
486 let e = serde_json::from_str::<ConditionOp>("3").unwrap_err();
487 assert_eq!(e.to_string(), "invalid type: integer `3`, expected a string at line 1 column 1");
488
489 let c = serde_json::from_str::<ConditionOp>("\"ArnEquals\"").unwrap();
490 assert_eq!(c, condop::ArnEquals);
491 }
492
493 #[test_log::test]
494 fn test_display() {
495 let items = vec![
496 "ArnEquals",
497 "ArnEqualsIfExists",
498 "ArnLike",
499 "ArnLikeIfExists",
500 "ArnNotEquals",
501 "ArnNotEqualsIfExists",
502 "ArnNotLike",
503 "ArnNotLikeIfExists",
504 "BinaryEquals",
505 "BinaryEqualsIfExists",
506 "Bool",
507 "BoolIfExists",
508 "DateEquals",
509 "DateEqualsIfExists",
510 "DateGreaterThan",
511 "DateGreaterThanEquals",
512 "DateGreaterThanEqualsIfExists",
513 "DateGreaterThanIfExists",
514 "DateLessThan",
515 "DateLessThanEquals",
516 "DateLessThanEqualsIfExists",
517 "DateLessThanIfExists",
518 "DateNotEquals",
519 "DateNotEqualsIfExists",
520 "IpAddress",
521 "IpAddressIfExists",
522 "NotIpAddress",
523 "NotIpAddressIfExists",
524 "Null",
525 "NumericEquals",
526 "NumericEqualsIfExists",
527 "NumericGreaterThan",
528 "NumericGreaterThanEquals",
529 "NumericGreaterThanEqualsIfExists",
530 "NumericGreaterThanIfExists",
531 "NumericLessThan",
532 "NumericLessThanEquals",
533 "NumericLessThanEqualsIfExists",
534 "NumericLessThanIfExists",
535 "NumericNotEquals",
536 "NumericNotEqualsIfExists",
537 "StringEquals",
538 "StringEqualsIfExists",
539 "StringEqualsIgnoreCase",
540 "StringEqualsIgnoreCaseIfExists",
541 "StringLike",
542 "StringLikeIfExists",
543 "StringNotEquals",
544 "StringNotEqualsIfExists",
545 "StringNotEqualsIgnoreCase",
546 "StringNotEqualsIgnoreCaseIfExists",
547 "StringNotLike",
548 "StringNotLikeIfExists",
549 ];
550
551 for item in items {
552 let op = ConditionOp::from_str(item).unwrap();
553 assert_eq!(format!("{op}"), item);
554 assert_eq!(&op, item);
555 }
556 }
557}