use std::fmt::Debug; use rocket::form::{Form, FromForm}; use rocket::form::error::{Error, Errors, ErrorKind}; #[derive(Debug, FromForm)] struct Cat<'v> { #[field(validate = len(5..))] name: &'v str, #[field(validate = starts_with("kitty"))] nick: &'v str, } #[derive(Debug, FromForm)] struct Dog<'v> { #[field(validate = len(5..))] name: &'v str, } #[derive(Debug, FromForm)] struct Person<'v> { kitty: Cat<'v>, #[field(validate = len(1..))] cats: Vec>, dog: Dog<'v>, } fn starts_with<'v, S: AsRef>(string: S, prefix: &str) -> Result<(), Errors<'v>> { if !string.as_ref().starts_with(prefix) { Err(Error::validation(format!("must start with {:?}", prefix)))? } Ok(()) } #[track_caller] fn errors<'v, T: FromForm<'v> + Debug + 'v>(string: &'v str) -> Errors<'v> { Form::::parse(string).expect_err("expected an error") } #[test] fn test_form_validation_context() { use ErrorKind::*; fn count<'a, K>(c: &Errors<'_>, n: &str, kind: K, fuzz: bool) -> usize where K: Into>> { let kind = kind.into(); c.iter().filter(|e| { let matches = (fuzz && e.is_for(n)) || (!fuzz && e.is_for_exactly(n)); let kinded = kind.as_ref().map(|k| k == &e.kind).unwrap_or(true); matches && kinded }).count() } fn fuzzy<'a, K>(c: &Errors<'_>, n: &str, kind: K) -> usize where K: Into>> { count(c, n, kind, true) } fn exact<'a, K>(c: &Errors<'_>, n: &str, kind: K) -> usize where K: Into>> { count(c, n, kind, false) } let c = errors::("name=littlebobby"); assert_eq!(exact(&c, "nick", Missing), 1); assert_eq!(fuzzy(&c, "nick", Missing), 1); assert_eq!(fuzzy(&c, "nick", None), 1); let c = errors::("cats[0].name=Bob"); assert_eq!(exact(&c, "kitty", None), 1); assert_eq!(exact(&c, "kitty", Missing), 1); assert_eq!(exact(&c, "cats[0].nick", None), 1); assert_eq!(exact(&c, "cats[0].nick", Missing), 1); assert_eq!(exact(&c, "dog", None), 1); assert_eq!(exact(&c, "dog", Missing), 1); assert_eq!(exact(&c, "dog.name", None), 0); assert_eq!(exact(&c, "kitty.name", None), 0); assert_eq!(exact(&c, "kitty.nick", None), 0); assert_eq!(fuzzy(&c, "kitty", None), 1); assert_eq!(fuzzy(&c, "kitty.name", Missing), 1); assert_eq!(fuzzy(&c, "kitty.nick", Missing), 1); assert_eq!(fuzzy(&c, "cats[0].nick", Missing), 1); assert_eq!(fuzzy(&c, "dog.name", Missing), 1); assert_eq!(fuzzy(&c, "dog", None), 1); let c = errors::("cats[0].name=Bob&cats[0].nick=kit&kitty.name=Hi"); assert_eq!(exact(&c, "kitty.nick", Missing), 1); assert_eq!(exact(&c, "kitty", None), 0); assert_eq!(exact(&c, "dog", Missing), 1); assert_eq!(exact(&c, "dog", None), 1); assert_eq!(exact(&c, "cats[0].name", None), 1); assert_eq!(exact(&c, "cats[0].name", InvalidLength { min: Some(5), max: None }), 1); assert_eq!(exact(&c, "cats[0].nick", None), 1); assert_eq!(exact(&c, "cats[0].nick", Validation("must start with \"kitty\"".into())), 1); assert_eq!(fuzzy(&c, "kitty.nick", Missing), 1); assert_eq!(fuzzy(&c, "kitty.nick", None), 1); assert_eq!(fuzzy(&c, "kitty", None), 0); assert_eq!(fuzzy(&c, "dog.name", Missing), 1); assert_eq!(fuzzy(&c, "dog", Missing), 1); assert_eq!(fuzzy(&c, "cats[0].nick", None), 1); assert_eq!(exact(&c, "cats[0].name", None), 1); let c = errors::("kitty.name=Michael"); assert_eq!(exact(&c, "kitty.nick", Missing), 1); assert_eq!(exact(&c, "dog", Missing), 1); assert_eq!(exact(&c, "cats[0].name", None), 0); assert_eq!(exact(&c, "cats[0].nick", None), 0); assert_eq!(exact(&c, "cats", None), 1); assert_eq!(exact(&c, "cats", InvalidLength { min: Some(1), max: None }), 1); assert_eq!(fuzzy(&c, "kitty.nick", Missing), 1); assert_eq!(fuzzy(&c, "kitty.nick", None), 1); assert_eq!(fuzzy(&c, "dog", None), 1); assert_eq!(fuzzy(&c, "dog.name", Missing), 1); assert_eq!(exact(&c, "cats[0].name", None), 0); assert_eq!(exact(&c, "cats[0].nick", None), 0); let c = errors::("kitty.name=Michael&kitty.nick=kittykat&dog.name=woofy"); assert_eq!(c.iter().count(), 1); assert_eq!(exact(&c, "cats", None), 1); assert_eq!(exact(&c, "cats", InvalidLength { min: Some(1), max: None }), 1); assert_eq!(fuzzy(&c, "cats[0].name", None), 1); } // #[derive(Debug, FromForm)] // struct Person<'v> { // kitty: Cat<'v>, // #[field(validate = len(1..))] // cats: Vec>, // dog: Dog<'v>, // }