2020-05-22 17:55:20 +00:00
use crate ::primitive_type ::{ PrimitiveType , PrimitiveTypesBitMap } ;
2020-05-23 21:36:59 +00:00
use serde_json ::{ Map , Number , Value } ;
2020-05-16 20:55:02 +00:00
use std ::{
2020-05-16 23:03:51 +00:00
borrow ::Cow ,
2020-05-16 20:55:02 +00:00
error , fmt ,
fmt ::{ Error , Formatter } ,
io ,
iter ::{ empty , once } ,
2020-05-21 11:09:36 +00:00
str ::Utf8Error ,
2020-05-16 20:55:02 +00:00
string ::FromUtf8Error ,
} ;
2020-03-04 14:07:40 +00:00
2020-05-26 16:42:35 +00:00
/// The error type that happens when the input schema is not valid.
///
/// It includes cases when during validation a reference is resolved into an invalid schema,
/// which we can't know upfront because schemas can be in remote locations.
2020-03-04 14:07:40 +00:00
#[ derive(Debug, PartialEq) ]
pub enum CompilationError {
2020-05-26 16:42:35 +00:00
/// Invalid schema structure
2020-03-04 14:07:40 +00:00
SchemaError ,
}
2020-03-29 20:37:55 +00:00
impl error ::Error for CompilationError { }
impl fmt ::Display for CompilationError {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-29 20:37:55 +00:00
fn fmt ( & self , f : & mut Formatter < '_ > ) -> Result < ( ) , Error > {
write! ( f , " Schema compilation error " )
}
}
2020-03-04 14:07:40 +00:00
impl From < regex ::Error > for CompilationError {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( _ : regex ::Error ) -> Self {
CompilationError ::SchemaError
}
}
impl From < url ::ParseError > for CompilationError {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( _ : url ::ParseError ) -> Self {
CompilationError ::SchemaError
}
}
/// An error that can occur during validation.
#[ derive(Debug) ]
2020-05-16 23:03:51 +00:00
pub struct ValidationError < ' a > {
instance : Cow < ' a , Value > ,
2020-03-04 14:07:40 +00:00
kind : ValidationErrorKind ,
}
2020-05-26 16:42:35 +00:00
/// An iterator over instances of `ValidationError` that represent validation error for the
/// input instance.
///
/// # Examples
///
/// ```rust
/// use jsonschema::JSONSchema;
/// use serde_json::json;
///
/// let schema = json!({"maxLength": 5});
/// let instance = json!("foo");
/// if let Ok(compiled) = JSONSchema::compile(&schema, None) {
/// let result = compiled.validate(&instance);
/// if let Err(errors) = result {
/// for error in errors {
/// println!("Validation error: {}", error)
2020-05-17 15:35:11 +00:00
/// }
2020-05-26 16:42:35 +00:00
/// }
/// }
/// ```
2020-05-16 23:03:51 +00:00
pub type ErrorIterator < ' a > = Box < dyn Iterator < Item = ValidationError < ' a > > + Sync + Send + ' a > ;
2020-03-28 22:49:23 +00:00
// Empty iterator means no error happened
2020-05-20 13:42:28 +00:00
pub fn no_error < ' a > ( ) -> ErrorIterator < ' a > {
2020-03-28 22:49:23 +00:00
Box ::new ( empty ( ) )
}
// A wrapper for one error
2020-05-20 13:42:28 +00:00
pub fn error ( instance : ValidationError ) -> ErrorIterator {
2020-03-28 22:49:23 +00:00
Box ::new ( once ( instance ) )
}
2020-03-04 14:07:40 +00:00
/// Kinds of errors that may happen during validation
#[ derive(Debug) ]
pub enum ValidationErrorKind {
/// The input array contain more items than expected.
2020-05-16 20:55:02 +00:00
AdditionalItems { limit : usize } ,
2020-03-04 14:07:40 +00:00
/// The input value is not valid under any of the given schemas.
2020-05-16 20:55:02 +00:00
AnyOf ,
2020-03-04 14:07:40 +00:00
/// The input value doesn't match expected constant.
2020-05-16 20:55:02 +00:00
Constant { expected_value : Value } ,
2020-03-04 14:07:40 +00:00
/// The input array doesn't contain items conforming to the specified schema.
2020-05-16 20:55:02 +00:00
Contains ,
2020-03-04 14:07:40 +00:00
/// The input value doesn't match any of specified options.
2020-05-16 20:55:02 +00:00
Enum { options : Value } ,
2020-03-04 14:07:40 +00:00
/// Value is too large.
2020-05-16 20:55:02 +00:00
ExclusiveMaximum { limit : f64 } ,
2020-03-04 14:07:40 +00:00
/// Value is too small.
2020-05-16 20:55:02 +00:00
ExclusiveMinimum { limit : f64 } ,
2020-03-04 14:07:40 +00:00
/// Everything is invalid for `false` schema.
2020-05-16 20:55:02 +00:00
FalseSchema ,
2020-03-04 14:07:40 +00:00
/// If the referenced file is not found during ref resolution.
2020-05-16 20:55:02 +00:00
FileNotFound { error : io ::Error } ,
2020-03-04 14:07:40 +00:00
/// When the input doesn't match to the specified format.
2020-05-19 19:15:04 +00:00
Format { format : & 'static str } ,
2020-03-04 14:07:40 +00:00
/// May happen in `contentEncoding` validation if `base64` encoded data is invalid.
2020-05-16 20:55:02 +00:00
FromUtf8 { error : FromUtf8Error } ,
2020-05-21 11:09:36 +00:00
/// Invalid UTF-8 string during percent encoding when resolving happens
Utf8 { error : Utf8Error } ,
2020-03-04 14:07:40 +00:00
/// May happen during ref resolution when remote document is not a valid JSON.
2020-05-16 20:55:02 +00:00
JSONParse { error : serde_json ::Error } ,
2020-03-04 14:07:40 +00:00
/// `ref` value is not valid.
2020-05-16 20:55:02 +00:00
InvalidReference { reference : String } ,
2020-05-21 11:09:36 +00:00
/// Invalid URL, e.g. invalid port number or IP address
InvalidURL { error : url ::ParseError } ,
2020-03-04 14:07:40 +00:00
/// Too many items in an array.
2020-05-21 11:09:36 +00:00
MaxItems { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// Value is too large.
2020-05-16 20:55:02 +00:00
Maximum { limit : f64 } ,
2020-03-04 14:07:40 +00:00
/// String is too long.
2020-05-21 11:09:36 +00:00
MaxLength { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// Too many properties in an object.
2020-05-21 11:09:36 +00:00
MaxProperties { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// Too few items in an array.
2020-05-21 11:09:36 +00:00
MinItems { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// Value is too small.
2020-05-16 20:55:02 +00:00
Minimum { limit : f64 } ,
2020-03-04 14:07:40 +00:00
/// String is too short.
2020-05-21 11:09:36 +00:00
MinLength { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// Not enough properties in an object.
2020-05-21 11:09:36 +00:00
MinProperties { limit : u64 } ,
2020-03-04 14:07:40 +00:00
/// When some number is not a multiple of another number.
2020-05-16 20:55:02 +00:00
MultipleOf { multiple_of : f64 } ,
2020-03-04 14:07:40 +00:00
/// Negated schema failed validation.
2020-05-16 20:55:02 +00:00
Not { schema : Value } ,
2020-03-04 14:07:40 +00:00
/// The given schema is valid under more than one of the given schemas.
2020-05-16 20:55:02 +00:00
OneOfMultipleValid ,
2020-03-04 14:07:40 +00:00
/// The given schema is not valid under any on the given schemas.
2020-05-16 20:55:02 +00:00
OneOfNotValid ,
2020-03-04 14:07:40 +00:00
/// When the input doesn't match to a pattern.
2020-05-16 20:55:02 +00:00
Pattern { pattern : String } ,
2020-03-04 14:07:40 +00:00
/// When a required property is missing.
2020-05-16 20:55:02 +00:00
Required { property : String } ,
2020-05-21 11:09:36 +00:00
/// Any error that happens during network request via `reqwest` crate
Reqwest { error : reqwest ::Error } ,
2020-03-04 14:07:40 +00:00
/// Resolved schema failed to compile.
Schema ,
/// When the input value doesn't match one or multiple required types.
2020-05-16 20:55:02 +00:00
Type { kind : TypeKind } ,
2020-03-04 14:07:40 +00:00
/// When the input array has non-unique elements.
2020-05-16 20:55:02 +00:00
UniqueItems ,
2020-03-04 14:07:40 +00:00
/// Reference contains unknown scheme.
2020-05-16 20:55:02 +00:00
UnknownReferenceScheme { scheme : String } ,
2020-05-30 20:36:51 +00:00
/// Unexpected error. This usually represent a bug into the validation
Unexpected { validator_representation : String } ,
2020-03-04 14:07:40 +00:00
}
#[ derive(Debug) ]
pub enum TypeKind {
Single ( PrimitiveType ) ,
2020-05-22 17:55:20 +00:00
Multiple ( PrimitiveTypesBitMap ) ,
2020-03-04 14:07:40 +00:00
}
/// Shortcuts for creation of specific error kinds.
2020-05-16 23:03:51 +00:00
impl < ' a > ValidationError < ' a > {
pub ( crate ) fn into_owned ( self ) -> ValidationError < 'static > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( self . instance . into_owned ( ) ) ,
kind : self . kind ,
}
}
pub ( crate ) fn additional_items ( instance : & ' a Value , limit : usize ) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::AdditionalItems { limit } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn any_of ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::AnyOf ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-23 21:36:59 +00:00
pub ( crate ) fn constant_array (
instance : & ' a Value ,
expected_value : & [ Value ] ,
) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Constant {
2020-05-23 21:36:59 +00:00
expected_value : Value ::Array ( expected_value . to_vec ( ) ) ,
} ,
}
}
pub ( crate ) fn constant_boolean (
instance : & ' a Value ,
expected_value : bool ,
) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Constant {
expected_value : Value ::Bool ( expected_value ) ,
} ,
}
}
pub ( crate ) fn constant_null ( instance : & ' a Value ) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Constant {
expected_value : Value ::Null ,
} ,
}
}
pub ( crate ) fn constant_number (
instance : & ' a Value ,
expected_value : & Number ,
) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Constant {
expected_value : Value ::Number ( expected_value . clone ( ) ) ,
} ,
}
}
pub ( crate ) fn constant_object (
instance : & ' a Value ,
expected_value : & Map < String , Value > ,
) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Constant {
expected_value : Value ::Object ( expected_value . clone ( ) ) ,
} ,
}
}
pub ( crate ) fn constant_string (
instance : & ' a Value ,
expected_value : & str ,
) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Constant {
expected_value : Value ::String ( expected_value . to_string ( ) ) ,
2020-05-16 20:55:02 +00:00
} ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn contains ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Contains ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn enumeration ( instance : & ' a Value , options : & Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Enum {
options : options . clone ( ) ,
} ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn exclusive_maximum ( instance : & ' a Value , limit : f64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::ExclusiveMaximum { limit } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn exclusive_minimum ( instance : & ' a Value , limit : f64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::ExclusiveMinimum { limit } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn false_schema ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::FalseSchema ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn file_not_found ( error : io ::Error ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::FileNotFound { error } ,
2020-03-04 14:07:40 +00:00
}
}
2020-05-19 19:15:04 +00:00
pub ( crate ) fn format ( instance : & ' a Value , format : & 'static str ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Format { format } ,
2020-03-04 14:07:40 +00:00
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn from_utf8 ( error : FromUtf8Error ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::FromUtf8 { error } ,
2020-03-04 14:07:40 +00:00
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn json_parse ( error : serde_json ::Error ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::JSONParse { error } ,
2020-03-04 14:07:40 +00:00
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn invalid_reference ( reference : String ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::InvalidReference { reference } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn invalid_url ( error : url ::ParseError ) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Owned ( Value ::Null ) ,
kind : ValidationErrorKind ::InvalidURL { error } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn max_items ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MaxItems { limit } ,
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn maximum ( instance : & ' a Value , limit : f64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Maximum { limit } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn max_length ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MaxLength { limit } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn max_properties ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MaxProperties { limit } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn min_items ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MinItems { limit } ,
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn minimum ( instance : & ' a Value , limit : f64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Minimum { limit } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn min_length ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MinLength { limit } ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn min_properties ( instance : & ' a Value , limit : u64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MinProperties { limit } ,
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn multiple_of ( instance : & ' a Value , multiple_of : f64 ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::MultipleOf { multiple_of } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn not ( instance : & ' a Value , schema : Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Not { schema } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn one_of_multiple_valid ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::OneOfMultipleValid ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn one_of_not_valid ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::OneOfNotValid ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn pattern ( instance : & ' a Value , pattern : String ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Pattern { pattern } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn required ( instance : & ' a Value , property : String ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::Required { property } ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn reqwest ( error : reqwest ::Error ) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Owned ( Value ::Null ) ,
kind : ValidationErrorKind ::Reqwest { error } ,
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn schema ( ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-03-04 14:07:40 +00:00
kind : ValidationErrorKind ::Schema ,
}
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn single_type_error (
instance : & ' a Value ,
type_name : PrimitiveType ,
) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-03-04 14:07:40 +00:00
kind : ValidationErrorKind ::Type {
kind : TypeKind ::Single ( type_name ) ,
} ,
2020-05-16 20:55:02 +00:00
}
2020-03-04 14:07:40 +00:00
}
pub ( crate ) fn multiple_type_error (
2020-05-16 23:03:51 +00:00
instance : & ' a Value ,
2020-05-22 17:55:20 +00:00
types : PrimitiveTypesBitMap ,
2020-05-16 23:03:51 +00:00
) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-03-04 14:07:40 +00:00
kind : ValidationErrorKind ::Type {
kind : TypeKind ::Multiple ( types ) ,
} ,
2020-05-16 20:55:02 +00:00
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn unique_items ( instance : & ' a Value ) -> ValidationError < ' a > {
2020-05-16 20:55:02 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Borrowed ( instance ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::UniqueItems ,
}
2020-03-04 14:07:40 +00:00
}
2020-05-16 23:03:51 +00:00
pub ( crate ) fn unknown_reference_scheme ( scheme : String ) -> ValidationError < ' a > {
2020-03-04 14:07:40 +00:00
ValidationError {
2020-05-16 23:03:51 +00:00
instance : Cow ::Owned ( Value ::Null ) ,
2020-05-16 20:55:02 +00:00
kind : ValidationErrorKind ::UnknownReferenceScheme { scheme } ,
2020-03-04 14:07:40 +00:00
}
}
2020-05-30 20:36:51 +00:00
pub ( crate ) fn unexpected (
instance : & ' a Value ,
validator_representation : & str ,
) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Borrowed ( instance ) ,
kind : ValidationErrorKind ::Unexpected {
validator_representation : validator_representation . to_string ( ) ,
} ,
}
}
2020-05-21 11:09:36 +00:00
pub ( crate ) fn utf8 ( error : Utf8Error ) -> ValidationError < ' a > {
ValidationError {
instance : Cow ::Owned ( Value ::Null ) ,
kind : ValidationErrorKind ::Utf8 { error } ,
}
}
2020-03-04 14:07:40 +00:00
}
2020-05-26 17:34:00 +00:00
impl From < CompilationError > for ValidationError < '_ > {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( _ : CompilationError ) -> Self {
ValidationError ::schema ( )
}
}
2020-05-26 17:34:00 +00:00
impl error ::Error for ValidationError < '_ > { }
impl From < serde_json ::Error > for ValidationError < '_ > {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( err : serde_json ::Error ) -> Self {
ValidationError ::json_parse ( err )
}
}
2020-05-26 17:34:00 +00:00
impl From < io ::Error > for ValidationError < '_ > {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( err : io ::Error ) -> Self {
ValidationError ::file_not_found ( err )
}
}
2020-05-26 17:34:00 +00:00
impl From < FromUtf8Error > for ValidationError < '_ > {
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn from ( err : FromUtf8Error ) -> Self {
ValidationError ::from_utf8 ( err )
}
}
2020-05-26 17:34:00 +00:00
impl From < Utf8Error > for ValidationError < '_ > {
2020-05-21 11:09:36 +00:00
#[ inline ]
fn from ( err : Utf8Error ) -> Self {
ValidationError ::utf8 ( err )
}
}
2020-05-26 17:34:00 +00:00
impl From < url ::ParseError > for ValidationError < '_ > {
2020-05-21 11:09:36 +00:00
#[ inline ]
fn from ( err : url ::ParseError ) -> Self {
ValidationError ::invalid_url ( err )
}
}
2020-05-26 17:34:00 +00:00
impl From < reqwest ::Error > for ValidationError < '_ > {
2020-05-21 11:09:36 +00:00
#[ inline ]
fn from ( err : reqwest ::Error ) -> Self {
ValidationError ::reqwest ( err )
}
}
2020-03-04 14:07:40 +00:00
/// Textual representation of various validation errors.
2020-05-26 17:34:00 +00:00
impl fmt ::Display for ValidationError < '_ > {
2020-05-30 20:36:51 +00:00
#[ allow(clippy::too_many_lines) ] // The function is long but it does formatting only
2020-05-20 14:38:17 +00:00
#[ inline ]
2020-03-04 14:07:40 +00:00
fn fmt ( & self , f : & mut Formatter < '_ > ) -> fmt ::Result {
2020-05-16 20:55:02 +00:00
match & self . kind {
2020-03-04 14:07:40 +00:00
ValidationErrorKind ::Schema = > write! ( f , " Schema error " ) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::JSONParse { error } = > write! ( f , " {} " , error ) ,
2020-05-21 11:09:36 +00:00
ValidationErrorKind ::Reqwest { error } = > write! ( f , " {} " , error ) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::FileNotFound { error } = > write! ( f , " {} " , error ) ,
2020-05-21 11:09:36 +00:00
ValidationErrorKind ::InvalidURL { error } = > write! ( f , " {} " , error ) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::UnknownReferenceScheme { scheme } = > {
write! ( f , " Unknown scheme: {} " , scheme )
}
ValidationErrorKind ::Format { format } = > {
write! ( f , " '{}' is not a '{}' " , self . instance , format )
2020-03-04 14:07:40 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::AdditionalItems { limit } = > {
// It's safe to unwrap here as ValidationErrorKind::AdditionalItems is reported only in
// case of arrays with more items than expected
let extras : Vec < & Value > = self
. instance
. as_array ( )
2020-05-20 15:03:40 +00:00
. expect ( " Always valid " )
2020-05-16 20:55:02 +00:00
. iter ( )
. skip ( * limit )
. collect ( ) ;
2020-03-04 14:07:40 +00:00
let verb = {
if extras . len ( ) = = 1 {
" was "
} else {
" were "
}
} ;
write! (
f ,
" Additional items are not allowed ({} {} unexpected) " ,
extras
. iter ( )
. map ( | x | x . to_string ( ) )
. collect ::< Vec < String > > ( )
. join ( " , " ) ,
verb
)
}
2020-05-20 13:22:48 +00:00
ValidationErrorKind ::AnyOf | ValidationErrorKind ::OneOfNotValid = > write! (
2020-03-04 14:07:40 +00:00
f ,
" '{}' is not valid under any of the given schemas " ,
2020-05-16 20:55:02 +00:00
self . instance
) ,
ValidationErrorKind ::Contains = > write! (
f ,
" None of '{}' are valid under the given schema " ,
self . instance
2020-03-04 14:07:40 +00:00
) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::Constant { expected_value } = > {
write! ( f , " '{}' was expected " , expected_value )
}
ValidationErrorKind ::FromUtf8 { error } = > write! ( f , " {} " , error ) ,
2020-05-21 11:09:36 +00:00
ValidationErrorKind ::Utf8 { error } = > write! ( f , " {} " , error ) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::Enum { options } = > {
write! ( f , " '{}' is not one of '{}' " , self . instance , options )
2020-03-04 14:07:40 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::ExclusiveMaximum { limit } = > write! (
2020-03-04 14:07:40 +00:00
f ,
2020-03-29 19:28:39 +00:00
" {} is greater than or equal to the maximum of {} " ,
2020-05-16 20:55:02 +00:00
self . instance , limit
2020-03-04 14:07:40 +00:00
) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::ExclusiveMinimum { limit } = > write! (
2020-03-04 14:07:40 +00:00
f ,
2020-03-29 19:28:39 +00:00
" {} is less than or equal to the minimum of {} " ,
2020-05-16 20:55:02 +00:00
self . instance , limit
2020-03-04 14:07:40 +00:00
) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::FalseSchema = > {
write! ( f , " False schema does not allow '{}' " , self . instance )
2020-03-29 19:28:39 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::InvalidReference { reference } = > {
write! ( f , " Invalid reference: {} " , reference )
2020-03-29 19:28:39 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::Maximum { limit } = > write! (
f ,
" {} is greater than the maximum of {} " ,
self . instance , limit
) ,
ValidationErrorKind ::Minimum { limit } = > {
write! ( f , " {} is less than the minimum of {} " , self . instance , limit )
2020-03-04 14:07:40 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::MaxLength { limit } = > write! (
f ,
" '{}' is longer than {} character{} " ,
self . instance ,
limit ,
if * limit = = 1 { " " } else { " s " }
) ,
ValidationErrorKind ::MinLength { limit } = > write! (
f ,
" '{}' is shorter than {} character{} " ,
self . instance ,
limit ,
if * limit = = 1 { " " } else { " s " }
) ,
ValidationErrorKind ::MaxItems { limit } = > write! (
f ,
" {} has more than {} item{} " ,
self . instance ,
limit ,
if * limit = = 1 { " " } else { " s " }
) ,
ValidationErrorKind ::MinItems { limit } = > write! (
f ,
" {} has less than {} item{} " ,
self . instance ,
limit ,
if * limit = = 1 { " " } else { " s " }
) ,
ValidationErrorKind ::MaxProperties { limit } = > write! (
f ,
" {} has more than {} propert{} " ,
self . instance ,
limit ,
if * limit = = 1 { " y " } else { " ies " }
) ,
ValidationErrorKind ::MinProperties { limit } = > write! (
f ,
" {} has less than {} propert{} " ,
self . instance ,
limit ,
if * limit = = 1 { " y " } else { " ies " }
) ,
ValidationErrorKind ::Not { schema } = > {
write! ( f , " {} is not allowed for {} " , schema , self . instance )
2020-03-04 14:07:40 +00:00
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::OneOfMultipleValid = > write! (
2020-03-04 14:07:40 +00:00
f ,
" '{}' is valid under more than one of the given schemas " ,
2020-05-16 20:55:02 +00:00
self . instance
2020-03-04 14:07:40 +00:00
) ,
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::Pattern { pattern } = > {
write! ( f , " '{}' does not match '{}' " , self . instance , pattern )
}
ValidationErrorKind ::Required { property } = > {
2020-03-04 14:07:40 +00:00
write! ( f , " '{}' is a required property " , property )
}
2020-05-16 20:55:02 +00:00
ValidationErrorKind ::MultipleOf { multiple_of } = > {
write! ( f , " {} is not a multiple of {} " , self . instance , multiple_of )
}
ValidationErrorKind ::UniqueItems = > {
write! ( f , " '{}' has non-unique elements " , self . instance )
2020-03-04 14:07:40 +00:00
}
ValidationErrorKind ::Type {
2020-05-16 20:55:02 +00:00
kind : TypeKind ::Single ( type_ ) ,
} = > write! ( f , " '{}' is not of type '{}' " , self . instance , type_ ) ,
ValidationErrorKind ::Type {
kind : TypeKind ::Multiple ( types ) ,
} = > write! (
f ,
2020-05-14 17:58:59 +00:00
" '{}' is not of types {} " ,
2020-05-16 20:55:02 +00:00
self . instance ,
types
2020-05-22 17:55:20 +00:00
. into_iter ( )
2020-05-14 17:58:59 +00:00
. map ( | t | format! ( " ' {} ' " , t ) )
2020-05-16 20:55:02 +00:00
. collect ::< Vec < String > > ( )
. join ( " , " )
) ,
2020-05-30 20:36:51 +00:00
ValidationErrorKind ::Unexpected { validator_representation } = > write! (
f ,
" Unexpected validation error. Usually this reflect a bug in the keywords implementation. Please make sure to report the problem to {}. Instance: {}, Validator: {} " ,
env! ( " CARGO_PKG_REPOSITORY " ) ,
self . instance ,
validator_representation ,
)
2020-03-04 14:07:40 +00:00
}
}
}
#[ cfg(test) ]
mod tests {
use super ::* ;
use serde_json ::json ;
#[ test ]
2020-05-14 17:58:59 +00:00
fn single_type_error ( ) {
2020-03-04 14:07:40 +00:00
let instance = json! ( 42 ) ;
2020-05-14 17:58:59 +00:00
let err = ValidationError ::single_type_error ( & instance , PrimitiveType ::String ) ;
2020-05-23 16:50:58 +00:00
assert_eq! ( err . to_string ( ) , " '42' is not of type 'string' " )
2020-03-04 14:07:40 +00:00
}
2020-05-14 17:58:59 +00:00
#[ test ]
fn multiple_types_error ( ) {
let instance = json! ( 42 ) ;
let err = ValidationError ::multiple_type_error (
& instance ,
2020-05-22 17:55:20 +00:00
vec! [ PrimitiveType ::String , PrimitiveType ::Number ] . into ( ) ,
2020-05-14 17:58:59 +00:00
) ;
2020-05-23 16:50:58 +00:00
assert_eq! ( err . to_string ( ) , " '42' is not of types 'number', 'string' " )
2020-05-14 17:58:59 +00:00
}
2020-03-04 14:07:40 +00:00
}