diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e59021..7479456 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - **INTERNAL**. A new `Draft201909` variant for the `Draft` enum that is available only under the `draft201909` feature. This feature is considered private and should not be used outside of the testing context. It allows us to add features from the 2019-09 Draft without exposing them in the public API. Therefore, support for this draft can be added incrementally. - The `Draft` enum is now marked as `non_exhaustive`. +- `ValidationError::schema` was removed and the calls replaced by proper errors. ### Fixed diff --git a/bench_helpers/Cargo.lock b/bench_helpers/Cargo.lock index a2c1e57..69aec6d 100644 --- a/bench_helpers/Cargo.lock +++ b/bench_helpers/Cargo.lock @@ -2,30 +2,447 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bench_helpers" version = "0.1.0" dependencies = [ + "criterion", + "serde", "serde_json", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "half" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "serde" version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" @@ -37,3 +454,151 @@ dependencies = [ "ryu", "serde", ] + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/jsonschema/src/compilation/mod.rs b/jsonschema/src/compilation/mod.rs index cf76664..d23d741 100644 --- a/jsonschema/src/compilation/mod.rs +++ b/jsonschema/src/compilation/mod.rs @@ -5,8 +5,14 @@ pub(crate) mod context; pub(crate) mod options; use crate::{ - error::ErrorIterator, keywords, paths::InstancePath, resolver::Resolver, - schema_node::SchemaNode, validator::Validate, Draft, Output, ValidationError, + error::ErrorIterator, + keywords, + paths::{InstancePath, JSONPointer}, + primitive_type::{PrimitiveType, PrimitiveTypesBitMap}, + resolver::Resolver, + schema_node::SchemaNode, + validator::Validate, + Draft, Output, ValidationError, }; use ahash::AHashMap; use context::CompilationContext; @@ -169,7 +175,12 @@ pub(crate) fn compile_validators<'a, 'c>( Some(unmatched_keywords), )) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::single_type_error( + JSONPointer::default(), + relative_path, + reference, + PrimitiveType::String, + )) } } else { let mut validators = Vec::with_capacity(object.len()); @@ -218,7 +229,14 @@ pub(crate) fn compile_validators<'a, 'c>( )) } } - _ => Err(ValidationError::schema(schema)), + _ => Err(ValidationError::multiple_type_error( + JSONPointer::default(), + relative_path, + schema, + PrimitiveTypesBitMap::new() + .add_type(PrimitiveType::Boolean) + .add_type(PrimitiveType::Object), + )), } } diff --git a/jsonschema/src/error.rs b/jsonschema/src/error.rs index f1729fe..e90ccab 100644 --- a/jsonschema/src/error.rs +++ b/jsonschema/src/error.rs @@ -656,15 +656,6 @@ impl<'a> ValidationError<'a> { } } - pub(crate) fn schema(instance: &'a Value) -> ValidationError<'a> { - ValidationError { - instance_path: JSONPointer::default(), - instance: Cow::Borrowed(instance), - kind: ValidationErrorKind::Schema, - schema_path: JSONPointer::default(), - } - } - pub(crate) fn null_schema() -> ValidationError<'a> { ValidationError { instance_path: JSONPointer::default(), diff --git a/jsonschema/src/keywords/additional_items.rs b/jsonschema/src/keywords/additional_items.rs index 7f72590..f7f7c04 100644 --- a/jsonschema/src/keywords/additional_items.rs +++ b/jsonschema/src/keywords/additional_items.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::{boolean::FalseValidator, CompilationResult}, paths::{InstancePath, JSONPointer}, + primitive_type::{PrimitiveType, PrimitiveTypesBitMap}, schema_node::SchemaNode, validator::{format_validators, Validate}, }; @@ -153,7 +154,15 @@ pub(crate) fn compile<'a>( Some(FalseValidator::compile(schema_path)) } } - _ => Some(Err(ValidationError::schema(schema))), + _ => Some(Err(ValidationError::multiple_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveTypesBitMap::new() + .add_type(PrimitiveType::Object) + .add_type(PrimitiveType::Array) + .add_type(PrimitiveType::Boolean), + ))), } } else { None diff --git a/jsonschema/src/keywords/additional_properties.rs b/jsonschema/src/keywords/additional_properties.rs index bd91f1d..59ff428 100644 --- a/jsonschema/src/keywords/additional_properties.rs +++ b/jsonschema/src/keywords/additional_properties.rs @@ -1357,13 +1357,15 @@ fn compile_patterns<'a>( for (pattern, subschema) in obj { let pattern_context = keyword_context.with_path(pattern.to_string()); if let Ok(compiled_pattern) = Regex::new(pattern) { - if let Ok(node) = compile_validators(subschema, &pattern_context) { - compiled_patterns.push((compiled_pattern, node)); - } else { - return Err(ValidationError::schema(subschema)); - } + let node = compile_validators(subschema, &pattern_context)?; + compiled_patterns.push((compiled_pattern, node)); } else { - return Err(ValidationError::schema(subschema)); + return Err(ValidationError::format( + JSONPointer::default(), + keyword_context.clone().into_pointer(), + subschema, + "regex", + )); } } Ok(compiled_patterns) diff --git a/jsonschema/src/keywords/all_of.rs b/jsonschema/src/keywords/all_of.rs index 53571df..9c39f63 100644 --- a/jsonschema/src/keywords/all_of.rs +++ b/jsonschema/src/keywords/all_of.rs @@ -2,7 +2,8 @@ use crate::{ compilation::{compile_validators, context::CompilationContext, JSONSchema}, error::{ErrorIterator, ValidationError}, output::BasicOutput, - paths::InstancePath, + paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_iter_of_validators, format_validators, PartialApplication, Validate}, }; @@ -136,7 +137,12 @@ pub(crate) fn compile<'a>( Some(AllOfValidator::compile(items, context)) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Array, + ))) } } diff --git a/jsonschema/src/keywords/any_of.rs b/jsonschema/src/keywords/any_of.rs index db538dd..ea889fe 100644 --- a/jsonschema/src/keywords/any_of.rs +++ b/jsonschema/src/keywords/any_of.rs @@ -2,6 +2,7 @@ use crate::{ compilation::{compile_validators, context::CompilationContext, JSONSchema}, error::{error, no_error, ErrorIterator, ValidationError}, paths::InstancePath, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_iter_of_validators, PartialApplication, Validate}, }; @@ -34,7 +35,12 @@ impl AnyOfValidator { schema_path: keyword_context.into_pointer(), })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Array, + )) } } } diff --git a/jsonschema/src/keywords/contains.rs b/jsonschema/src/keywords/contains.rs index 15cae51..b09d670 100644 --- a/jsonschema/src/keywords/contains.rs +++ b/jsonschema/src/keywords/contains.rs @@ -3,12 +3,16 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_validators, PartialApplication, Validate}, Draft, }; use serde_json::{Map, Value}; +#[cfg(feature = "draft201909")] +use super::helpers::map_get_u64; + pub(crate) struct ContainsValidator { node: SchemaNode, schema_path: JSONPointer, @@ -422,33 +426,22 @@ pub(crate) fn compile<'a>( } #[cfg(feature = "draft201909")] Draft::Draft201909 => { - if let Some(min_contains) = parent.get("minContains") { - if let Some(min_contains) = min_contains.as_u64() { - if let Some(max_contains) = parent.get("maxContains") { - if let Some(max_contains) = max_contains.as_u64() { - Some(MinMaxContainsValidator::compile( - schema, - context, - min_contains, - max_contains, - )) - } else { - Some(Err(ValidationError::schema(schema))) - } - } else { - Some(MinContainsValidator::compile(schema, context, min_contains)) - } - } else { - Some(Err(ValidationError::schema(schema))) + let min_contains = match map_get_u64(parent, context, "minContains").transpose() { + Ok(n) => n, + Err(err) => return Some(Err(err)), + }; + let max_contains = match map_get_u64(parent, context, "maxContains").transpose() { + Ok(n) => n, + Err(err) => return Some(Err(err)), + }; + + match (min_contains, max_contains) { + (Some(min), Some(max)) => { + Some(MinMaxContainsValidator::compile(schema, context, min, max)) } - } else if let Some(max_contains) = parent.get("maxContains") { - if let Some(max_contains) = max_contains.as_u64() { - Some(MaxContainsValidator::compile(schema, context, max_contains)) - } else { - Some(Err(ValidationError::schema(schema))) - } - } else { - Some(ContainsValidator::compile(schema, context)) + (Some(min), None) => Some(MinContainsValidator::compile(schema, context, min)), + (None, Some(max)) => Some(MaxContainsValidator::compile(schema, context, max)), + (None, None) => Some(ContainsValidator::compile(schema, context)), } } } diff --git a/jsonschema/src/keywords/content.rs b/jsonschema/src/keywords/content.rs index e4e396c..b48cdb9 100644 --- a/jsonschema/src/keywords/content.rs +++ b/jsonschema/src/keywords/content.rs @@ -6,6 +6,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use serde_json::{Map, Value}; @@ -246,7 +247,12 @@ pub(crate) fn compile_media_type<'a>( context.schema_path.clone().into(), )) } - _ => Some(Err(ValidationError::schema(subschema))), + _ => Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + content_encoding, + PrimitiveType::String, + ))), } } else { Some(ContentMediaTypeValidator::compile( @@ -256,7 +262,12 @@ pub(crate) fn compile_media_type<'a>( )) } } - _ => Some(Err(ValidationError::schema(subschema))), + _ => Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + subschema, + PrimitiveType::String, + ))), } } @@ -286,7 +297,12 @@ pub(crate) fn compile_content_encoding<'a>( context.as_pointer_with("contentEncoding"), )) } - _ => Some(Err(ValidationError::schema(subschema))), + _ => Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + subschema, + PrimitiveType::String, + ))), } } diff --git a/jsonschema/src/keywords/dependencies.rs b/jsonschema/src/keywords/dependencies.rs index 38723b4..43a1f29 100644 --- a/jsonschema/src/keywords/dependencies.rs +++ b/jsonschema/src/keywords/dependencies.rs @@ -2,7 +2,8 @@ use crate::{ compilation::{compile_validators, context::CompilationContext, JSONSchema}, error::{no_error, ErrorIterator, ValidationError}, keywords::{required, CompilationResult}, - paths::InstancePath, + paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_key_value_validators, Validate}, }; @@ -38,7 +39,12 @@ impl DependenciesValidator { } Ok(Box::new(DependenciesValidator { dependencies })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Object, + )) } } } diff --git a/jsonschema/src/keywords/enum_.rs b/jsonschema/src/keywords/enum_.rs index 23cf247..4e2c073 100644 --- a/jsonschema/src/keywords/enum_.rs +++ b/jsonschema/src/keywords/enum_.rs @@ -153,7 +153,12 @@ pub(crate) fn compile<'a>( Some(EnumValidator::compile(schema, items, schema_path)) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Array, + ))) } } diff --git a/jsonschema/src/keywords/exclusive_maximum.rs b/jsonschema/src/keywords/exclusive_maximum.rs index 9793d3b..5b78ba0 100644 --- a/jsonschema/src/keywords/exclusive_maximum.rs +++ b/jsonschema/src/keywords/exclusive_maximum.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use num_cmp::NumCmp; @@ -140,7 +141,12 @@ pub(crate) fn compile<'a>( }))) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Number, + ))) } } diff --git a/jsonschema/src/keywords/exclusive_minimum.rs b/jsonschema/src/keywords/exclusive_minimum.rs index 34b13dc..9e17a01 100644 --- a/jsonschema/src/keywords/exclusive_minimum.rs +++ b/jsonschema/src/keywords/exclusive_minimum.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use num_cmp::NumCmp; @@ -138,7 +139,12 @@ pub(crate) fn compile<'a>( }))) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Number, + ))) } } diff --git a/jsonschema/src/keywords/format.rs b/jsonschema/src/keywords/format.rs index ca4319d..ef45a35 100644 --- a/jsonschema/src/keywords/format.rs +++ b/jsonschema/src/keywords/format.rs @@ -12,6 +12,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::{pattern, CompilationResult}, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, Draft, }; @@ -488,7 +489,12 @@ pub(crate) fn compile<'a>( _ => None, } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::String, + ))) } } diff --git a/jsonschema/src/keywords/helpers.rs b/jsonschema/src/keywords/helpers.rs index d1a000e..3696c20 100644 --- a/jsonschema/src/keywords/helpers.rs +++ b/jsonschema/src/keywords/helpers.rs @@ -1,6 +1,11 @@ use num_cmp::NumCmp; use serde_json::{Map, Value}; +use crate::{ + compilation::context::CompilationContext, paths::JSONPointer, primitive_type::PrimitiveType, + ValidationError, +}; + macro_rules! num_cmp { ($left:expr, $right:expr) => { if let Some(b) = $right.as_u64() { @@ -49,6 +54,30 @@ pub(crate) fn equal_objects(left: &Map, right: &Map( + m: &'a Map, + context: &CompilationContext, + type_name: &str, +) -> Option>> { + let value = m.get(type_name)?; + match value.as_u64() { + Some(n) => Some(Ok(n)), + None if value.as_i64().is_some() => Some(Err(ValidationError::minimum( + JSONPointer::default(), + context.clone().into_pointer(), + value, + 0.into(), + ))), + None => Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + value, + PrimitiveType::Integer, + ))), + } +} + #[cfg(test)] mod tests { use super::equal; diff --git a/jsonschema/src/keywords/legacy/type_draft_4.rs b/jsonschema/src/keywords/legacy/type_draft_4.rs index aa35cb1..ea2b1cb 100644 --- a/jsonschema/src/keywords/legacy/type_draft_4.rs +++ b/jsonschema/src/keywords/legacy/type_draft_4.rs @@ -6,7 +6,7 @@ use crate::{ primitive_type::{PrimitiveType, PrimitiveTypesBitMap}, validator::Validate, }; -use serde_json::{Map, Number, Value}; +use serde_json::{json, Map, Number, Value}; use std::convert::TryFrom; pub(crate) struct MultipleTypesValidator { @@ -24,10 +24,24 @@ impl MultipleTypesValidator { if let Ok(primitive_type) = PrimitiveType::try_from(string.as_str()) { types |= primitive_type; } else { - return Err(ValidationError::schema(item)); + return Err(ValidationError::enumeration( + JSONPointer::default(), + schema_path, + item, + &json!([ + "array", "boolean", "integer", "null", "number", "object", "string" + ]), + )); } } - _ => return Err(ValidationError::schema(item)), + _ => { + return Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + item, + PrimitiveType::String, + )) + } } } Ok(Box::new(MultipleTypesValidator { types, schema_path })) @@ -141,16 +155,29 @@ pub(crate) fn compile<'a>( Value::String(item) => compile_single_type(item.as_str(), schema_path), Value::Array(items) => { if items.len() == 1 { - if let Some(Value::String(item)) = items.iter().next() { + let item = &items[0]; + if let Value::String(item) = item { compile_single_type(item.as_str(), schema_path) } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + item, + PrimitiveType::String, + ))) } } else { Some(MultipleTypesValidator::compile(items, schema_path)) } } - _ => Some(Err(ValidationError::schema(schema))), + _ => Some(Err(ValidationError::multiple_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveTypesBitMap::new() + .add_type(PrimitiveType::String) + .add_type(PrimitiveType::Array), + ))), } } diff --git a/jsonschema/src/keywords/max_items.rs b/jsonschema/src/keywords/max_items.rs index f9389ea..2779e75 100644 --- a/jsonschema/src/keywords/max_items.rs +++ b/jsonschema/src/keywords/max_items.rs @@ -18,7 +18,12 @@ impl MaxItemsValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MaxItemsValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "max_items int validation", + )) } } } diff --git a/jsonschema/src/keywords/max_length.rs b/jsonschema/src/keywords/max_length.rs index 73ef266..59b0f6f 100644 --- a/jsonschema/src/keywords/max_length.rs +++ b/jsonschema/src/keywords/max_length.rs @@ -18,7 +18,12 @@ impl MaxLengthValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MaxLengthValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "max_length int validation", + )) } } } diff --git a/jsonschema/src/keywords/max_properties.rs b/jsonschema/src/keywords/max_properties.rs index db378a4..d04256a 100644 --- a/jsonschema/src/keywords/max_properties.rs +++ b/jsonschema/src/keywords/max_properties.rs @@ -18,7 +18,12 @@ impl MaxPropertiesValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MaxPropertiesValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "max_properties int validation", + )) } } } diff --git a/jsonschema/src/keywords/maximum.rs b/jsonschema/src/keywords/maximum.rs index 078a37e..8d8bb90 100644 --- a/jsonschema/src/keywords/maximum.rs +++ b/jsonschema/src/keywords/maximum.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use num_cmp::NumCmp; @@ -138,7 +139,12 @@ pub(crate) fn compile<'a>( }))) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Number, + ))) } } diff --git a/jsonschema/src/keywords/min_items.rs b/jsonschema/src/keywords/min_items.rs index cb1c281..277cf8b 100644 --- a/jsonschema/src/keywords/min_items.rs +++ b/jsonschema/src/keywords/min_items.rs @@ -18,7 +18,12 @@ impl MinItemsValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MinItemsValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "min_length int validation", + )) } } } diff --git a/jsonschema/src/keywords/min_length.rs b/jsonschema/src/keywords/min_length.rs index 46789a5..75418c8 100644 --- a/jsonschema/src/keywords/min_length.rs +++ b/jsonschema/src/keywords/min_length.rs @@ -18,7 +18,12 @@ impl MinLengthValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MinLengthValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "min_length int validation", + )) } } } diff --git a/jsonschema/src/keywords/min_properties.rs b/jsonschema/src/keywords/min_properties.rs index 2536f45..882bc82 100644 --- a/jsonschema/src/keywords/min_properties.rs +++ b/jsonschema/src/keywords/min_properties.rs @@ -18,7 +18,12 @@ impl MinPropertiesValidator { if let Some(limit) = schema.as_u64() { Ok(Box::new(MinPropertiesValidator { limit, schema_path })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::format( + JSONPointer::default(), + schema_path, + schema, + "min_properties int validation", + )) } } } diff --git a/jsonschema/src/keywords/minimum.rs b/jsonschema/src/keywords/minimum.rs index 4878c1a..a50c876 100644 --- a/jsonschema/src/keywords/minimum.rs +++ b/jsonschema/src/keywords/minimum.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use num_cmp::NumCmp; @@ -138,7 +139,12 @@ pub(crate) fn compile<'a>( }))) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Number, + ))) } } diff --git a/jsonschema/src/keywords/multiple_of.rs b/jsonschema/src/keywords/multiple_of.rs index 9341cbd..d91eedc 100644 --- a/jsonschema/src/keywords/multiple_of.rs +++ b/jsonschema/src/keywords/multiple_of.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use fraction::{BigFraction, BigUint}; @@ -139,7 +140,12 @@ pub(crate) fn compile<'a>( Some(MultipleOfFloatValidator::compile(multiple_of, schema_path)) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Number, + ))) } } diff --git a/jsonschema/src/keywords/one_of.rs b/jsonschema/src/keywords/one_of.rs index c821468..adc23fd 100644 --- a/jsonschema/src/keywords/one_of.rs +++ b/jsonschema/src/keywords/one_of.rs @@ -4,6 +4,7 @@ use crate::{ keywords::CompilationResult, output::BasicOutput, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_iter_of_validators, PartialApplication, Validate}, }; @@ -33,7 +34,12 @@ impl OneOfValidator { schema_path: keyword_context.into_pointer(), })) } else { - Err(ValidationError::schema(schema)) + Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Array, + )) } } diff --git a/jsonschema/src/keywords/pattern.rs b/jsonschema/src/keywords/pattern.rs index 0e20111..f6d1273 100644 --- a/jsonschema/src/keywords/pattern.rs +++ b/jsonschema/src/keywords/pattern.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::InstancePath, + primitive_type::PrimitiveType, validator::Validate, }; use serde_json::{Map, Value}; @@ -31,7 +32,14 @@ impl PatternValidator { Value::String(item) => { let pattern = match convert_regex(item) { Ok(r) => r, - Err(_) => return Err(ValidationError::schema(pattern)), + Err(_) => { + return Err(ValidationError::format( + JSONPointer::default(), + context.clone().into_pointer(), + pattern, + "regex", + )) + } }; Ok(Box::new(PatternValidator { original: item.clone(), @@ -39,7 +47,12 @@ impl PatternValidator { schema_path: context.as_pointer_with("pattern"), })) } - _ => Err(ValidationError::schema(pattern)), + _ => Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + pattern, + PrimitiveType::String, + )), } } } diff --git a/jsonschema/src/keywords/pattern_properties.rs b/jsonschema/src/keywords/pattern_properties.rs index 1f1f604..62ce2e6 100644 --- a/jsonschema/src/keywords/pattern_properties.rs +++ b/jsonschema/src/keywords/pattern_properties.rs @@ -3,7 +3,8 @@ use crate::{ error::{no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, output::BasicOutput, - paths::InstancePath, + paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_validators, PartialApplication, Validate}, }; @@ -27,7 +28,14 @@ impl PatternPropertiesValidator { patterns.push(( match Regex::new(pattern) { Ok(r) => r, - Err(_) => return Err(ValidationError::schema(subschema)), + Err(_) => { + return Err(ValidationError::format( + JSONPointer::default(), + keyword_context.clone().into_pointer(), + subschema, + "regex", + )) + } }, compile_validators(subschema, &pattern_context)?, )); @@ -133,7 +141,14 @@ impl SingleValuePatternPropertiesValidator { Ok(Box::new(SingleValuePatternPropertiesValidator { pattern: match Regex::new(pattern) { Ok(r) => r, - Err(_) => return Err(ValidationError::schema(schema)), + Err(_) => { + return Err(ValidationError::format( + JSONPointer::default(), + keyword_context.clone().into_pointer(), + schema, + "regex", + )) + } }, node: compile_validators(schema, &pattern_context)?, })) @@ -229,7 +244,12 @@ pub(crate) fn compile<'a>( Some(PatternPropertiesValidator::compile(map, context)) } } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Object, + ))) } } } diff --git a/jsonschema/src/keywords/properties.rs b/jsonschema/src/keywords/properties.rs index 8f74089..0166436 100644 --- a/jsonschema/src/keywords/properties.rs +++ b/jsonschema/src/keywords/properties.rs @@ -3,7 +3,8 @@ use crate::{ error::{no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, output::BasicOutput, - paths::InstancePath, + paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, schema_node::SchemaNode, validator::{format_key_value_validators, PartialApplication, Validate}, }; @@ -32,7 +33,12 @@ impl PropertiesValidator { } Ok(Box::new(PropertiesValidator { properties })) } - _ => Err(ValidationError::schema(schema)), + _ => Err(ValidationError::single_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveType::Object, + )), } } } diff --git a/jsonschema/src/keywords/required.rs b/jsonschema/src/keywords/required.rs index 5d31a8c..3b1759d 100644 --- a/jsonschema/src/keywords/required.rs +++ b/jsonschema/src/keywords/required.rs @@ -3,6 +3,7 @@ use crate::{ error::{error, no_error, ErrorIterator, ValidationError}, keywords::CompilationResult, paths::{InstancePath, JSONPointer}, + primitive_type::PrimitiveType, validator::Validate, }; use serde_json::{Map, Value}; @@ -19,7 +20,14 @@ impl RequiredValidator { for item in items { match item { Value::String(string) => required.push(string.clone()), - _ => return Err(ValidationError::schema(item)), + _ => { + return Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + item, + PrimitiveType::String, + )) + } } } Ok(Box::new(RequiredValidator { @@ -141,16 +149,27 @@ pub(crate) fn compile_with_path( match schema { Value::Array(items) => { if items.len() == 1 { - if let Some(Value::String(item)) = items.iter().next() { + let item = &items[0]; + if let Value::String(item) = item { Some(SingleItemRequiredValidator::compile(item, schema_path)) } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + item, + PrimitiveType::String, + ))) } } else { Some(RequiredValidator::compile(items, schema_path)) } } - _ => Some(Err(ValidationError::schema(schema))), + _ => Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + schema, + PrimitiveType::Array, + ))), } } diff --git a/jsonschema/src/keywords/type_.rs b/jsonschema/src/keywords/type_.rs index 99429ee..9dfd287 100644 --- a/jsonschema/src/keywords/type_.rs +++ b/jsonschema/src/keywords/type_.rs @@ -5,7 +5,7 @@ use crate::{ primitive_type::{PrimitiveType, PrimitiveTypesBitMap}, validator::Validate, }; -use serde_json::{Map, Number, Value}; +use serde_json::{json, Map, Number, Value}; use std::convert::TryFrom; use crate::paths::{InstancePath, JSONPointer}; @@ -25,10 +25,24 @@ impl MultipleTypesValidator { if let Ok(primitive_type) = PrimitiveType::try_from(string.as_str()) { types |= primitive_type; } else { - return Err(ValidationError::schema(item)); + return Err(ValidationError::enumeration( + JSONPointer::default(), + schema_path, + item, + &json!([ + "array", "boolean", "integer", "null", "number", "object", "string" + ]), + )); } } - _ => return Err(ValidationError::schema(item)), + _ => { + return Err(ValidationError::single_type_error( + schema_path, + JSONPointer::default(), + item, + PrimitiveType::String, + )) + } } } Ok(Box::new(MultipleTypesValidator { types, schema_path })) @@ -380,16 +394,29 @@ pub(crate) fn compile<'a>( Value::String(item) => compile_single_type(item.as_str(), schema_path), Value::Array(items) => { if items.len() == 1 { - if let Some(Value::String(item)) = items.iter().next() { + let item = &items[0]; + if let Value::String(item) = item { compile_single_type(item.as_str(), schema_path) } else { - Some(Err(ValidationError::schema(schema))) + Some(Err(ValidationError::single_type_error( + JSONPointer::default(), + schema_path, + item, + PrimitiveType::String, + ))) } } else { Some(MultipleTypesValidator::compile(items, schema_path)) } } - _ => Some(Err(ValidationError::schema(schema))), + _ => Some(Err(ValidationError::multiple_type_error( + JSONPointer::default(), + context.clone().into_pointer(), + schema, + PrimitiveTypesBitMap::new() + .add_type(PrimitiveType::String) + .add_type(PrimitiveType::Array), + ))), } }