#![warn(
clippy::cast_possible_truncation,
clippy::doc_markdown,
clippy::explicit_iter_loop,
clippy::map_unwrap_or,
clippy::match_same_arms,
clippy::needless_borrow,
clippy::needless_pass_by_value,
clippy::print_stdout,
clippy::redundant_closure,
clippy::trivially_copy_pass_by_ref,
clippy::missing_const_for_fn,
clippy::unseparated_literal_suffix,
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unreachable_pub,
variant_size_differences
)]
#![allow(
clippy::unnecessary_wraps,
clippy::upper_case_acronyms,
clippy::needless_collect
)]
#![cfg_attr(not(test), allow(clippy::arithmetic_side_effects, clippy::unwrap_used))]
mod compilation;
mod content_encoding;
mod content_media_type;
pub mod error;
mod keywords;
pub mod output;
pub mod paths;
pub mod primitive_type;
pub(crate) mod properties;
mod resolver;
mod schema_node;
mod schemas;
mod validator;
pub use compilation::{options::CompilationOptions, JSONSchema};
pub use error::{ErrorIterator, ValidationError};
pub use keywords::custom::Keyword;
pub use resolver::{SchemaResolver, SchemaResolverError};
pub use schemas::Draft;
use serde_json::Value;
#[must_use]
#[inline]
pub fn is_valid(schema: &Value, instance: &Value) -> bool {
let compiled = JSONSchema::compile(schema).expect("Invalid schema");
compiled.is_valid(instance)
}
#[cfg(test)]
pub(crate) mod tests_util {
use super::JSONSchema;
use crate::ValidationError;
use serde_json::Value;
fn is_not_valid_inner(compiled: &JSONSchema, instance: &Value) {
assert!(
!compiled.is_valid(instance),
"{} should not be valid (via is_valid)",
instance
);
assert!(
compiled.validate(instance).is_err(),
"{} should not be valid (via validate)",
instance
);
assert!(
!compiled.apply(instance).basic().is_valid(),
"{} should not be valid (via apply)",
instance
);
}
pub(crate) fn is_not_valid(schema: &Value, instance: &Value) {
let compiled = JSONSchema::compile(schema).unwrap();
is_not_valid_inner(&compiled, instance)
}
#[cfg(any(feature = "draft201909", feature = "draft202012"))]
pub(crate) fn is_not_valid_with_draft(draft: crate::Draft, schema: &Value, instance: &Value) {
let compiled = JSONSchema::options()
.with_draft(draft)
.compile(schema)
.unwrap();
is_not_valid_inner(&compiled, instance)
}
pub(crate) fn expect_errors(schema: &Value, instance: &Value, errors: &[&str]) {
assert_eq!(
JSONSchema::compile(schema)
.expect("Should be a valid schema")
.validate(instance)
.expect_err(format!("{} should not be valid", instance).as_str())
.map(|e| e.to_string())
.collect::<Vec<String>>(),
errors
)
}
fn is_valid_inner(compiled: &JSONSchema, instance: &Value) {
assert!(
compiled.is_valid(instance),
"{} should be valid (via is_valid)",
instance
);
assert!(
compiled.validate(instance).is_ok(),
"{} should be valid (via validate)",
instance
);
assert!(
compiled.apply(instance).basic().is_valid(),
"{} should be valid (via apply)",
instance
);
}
pub(crate) fn is_valid(schema: &Value, instance: &Value) {
let compiled = JSONSchema::compile(schema).unwrap();
is_valid_inner(&compiled, instance);
}
#[cfg(any(feature = "draft201909", feature = "draft202012"))]
pub(crate) fn is_valid_with_draft(draft: crate::Draft, schema: &Value, instance: &Value) {
let compiled = JSONSchema::options()
.with_draft(draft)
.compile(schema)
.unwrap();
is_valid_inner(&compiled, instance)
}
pub(crate) fn validate(schema: &Value, instance: &Value) -> ValidationError<'static> {
let compiled = JSONSchema::compile(schema).unwrap();
let err = compiled
.validate(instance)
.expect_err("Should be an error")
.next()
.expect("Should be an error")
.into_owned();
err
}
pub(crate) fn assert_schema_path(schema: &Value, instance: &Value, expected: &str) {
let error = validate(schema, instance);
assert_eq!(error.schema_path.to_string(), expected)
}
pub(crate) fn assert_schema_paths(schema: &Value, instance: &Value, expected: &[&str]) {
let compiled = JSONSchema::compile(schema).unwrap();
let errors = compiled.validate(instance).expect_err("Should be an error");
for (error, schema_path) in errors.zip(expected) {
assert_eq!(error.schema_path.to_string(), *schema_path)
}
}
}
#[cfg(test)]
mod tests {
use super::{is_valid, Draft, JSONSchema};
use serde_json::json;
use test_case::test_case;
#[test]
fn test_is_valid() {
let schema = json!({"minLength": 5});
let valid = json!("foobar");
let invalid = json!("foo");
assert!(is_valid(&schema, &valid));
assert!(!is_valid(&schema, &invalid));
}
#[test_case(Draft::Draft4)]
#[test_case(Draft::Draft6)]
#[test_case(Draft::Draft7)]
fn meta_schemas(draft: Draft) {
for schema in [json!({"enum": [0, 0.0]}), json!({"enum": []})] {
assert!(JSONSchema::options()
.with_draft(draft)
.compile(&schema)
.is_ok())
}
}
#[test]
fn incomplete_escape_in_pattern() {
let schema = json!({"pattern": "\\u"});
assert!(JSONSchema::compile(&schema).is_err())
}
}