From d27f9be146609c39d723f28dc7d8a9ee261eccae Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Tue, 10 Sep 2024 21:33:50 +0200 Subject: [PATCH] fix: Ignoring $schema in resolved references Signed-off-by: Dmitry Dygalo --- CHANGELOG.md | 8 + bindings/python/CHANGELOG.md | 8 + bindings/python/benches/bench.py | 8 +- bindings/python/src/lib.rs | 19 +- bindings/python/tests-py/test_suite.py | 2 +- jsonschema/benches/jsonschema.rs | 3 +- jsonschema/src/compilation/options.rs | 235 +++++++++++++------------ jsonschema/src/keywords/ref_.rs | 92 ++++++++-- jsonschema/src/lib.rs | 12 +- jsonschema/src/resolver.rs | 6 +- jsonschema/tests/test_suite.rs | 2 - 11 files changed, 245 insertions(+), 150 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e297875c..457fe5af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased] +### Fixed + +- Ignoring `$schema` in resolved references. + +### Deprecated + +- `with_meta_schemas()` method. Meta schemas are included by default. + ## [0.18.1] - 2024-08-24 ### Added diff --git a/bindings/python/CHANGELOG.md b/bindings/python/CHANGELOG.md index 0fa36c38..8ad6f339 100644 --- a/bindings/python/CHANGELOG.md +++ b/bindings/python/CHANGELOG.md @@ -2,6 +2,14 @@ ## [Unreleased] +### Fixed + +- Ignoring ``$schema`` in resolved references. + +### Deprecated + +- `with_meta_schemas` argument. Meta schemas are included by default. + ## [0.18.1] - 2024-08-24 ### Changed diff --git a/bindings/python/benches/bench.py b/bindings/python/benches/bench.py index 4c7d91d6..ab4cbda6 100644 --- a/bindings/python/benches/bench.py +++ b/bindings/python/benches/bench.py @@ -83,19 +83,19 @@ def args(request, variant, is_compiled): schema, instance = request.node.get_closest_marker("data").args if variant == "jsonschema-rs-is-valid": if is_compiled: - return jsonschema_rs.JSONSchema(schema, with_meta_schemas=True).is_valid, instance + return jsonschema_rs.JSONSchema(schema).is_valid, instance else: return ( - partial(jsonschema_rs.is_valid, with_meta_schemas=True), + jsonschema_rs.is_valid, schema, instance, ) if variant == "jsonschema-rs-validate": if is_compiled: - return jsonschema_rs.JSONSchema(schema, with_meta_schemas=True).validate, instance + return jsonschema_rs.JSONSchema(schema).validate, instance else: return ( - partial(jsonschema_rs.validate, with_meta_schemas=True), + jsonschema_rs.validate, schema, instance, ) diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index fe1e3842..5e3bed43 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -140,16 +140,12 @@ thread_local! { fn make_options( draft: Option, - with_meta_schemas: Option, formats: Option<&Bound<'_, PyDict>>, ) -> PyResult { let mut options = jsonschema::JSONSchema::options(); if let Some(raw_draft_version) = draft { options.with_draft(get_draft(raw_draft_version)?); } - if with_meta_schemas == Some(true) { - options.with_meta_schemas(); - } if let Some(formats) = formats { for (name, callback) in formats.iter() { if !callback.is_callable() { @@ -284,6 +280,7 @@ fn to_error_message(error: &jsonschema::ValidationError<'_>) -> String { /// If your workflow implies validating against the same schema, consider using `JSONSchema.is_valid` /// instead. #[pyfunction] +#[allow(unused_variables)] #[pyo3(signature = (schema, instance, draft=None, with_meta_schemas=false, formats=None))] fn is_valid( py: Python<'_>, @@ -293,7 +290,7 @@ fn is_valid( with_meta_schemas: Option, formats: Option<&Bound<'_, PyDict>>, ) -> PyResult { - let options = make_options(draft, with_meta_schemas, formats)?; + let options = make_options(draft, formats)?; let schema = ser::to_value(schema)?; match options.compile(&schema) { Ok(compiled) => { @@ -317,6 +314,7 @@ fn is_valid( /// If your workflow implies validating against the same schema, consider using `JSONSchema.validate` /// instead. #[pyfunction] +#[allow(unused_variables)] #[pyo3(signature = (schema, instance, draft=None, with_meta_schemas=false, formats=None))] fn validate( py: Python<'_>, @@ -326,7 +324,7 @@ fn validate( with_meta_schemas: Option, formats: Option<&Bound<'_, PyDict>>, ) -> PyResult<()> { - let options = make_options(draft, with_meta_schemas, formats)?; + let options = make_options(draft, formats)?; let schema = ser::to_value(schema)?; match options.compile(&schema) { Ok(compiled) => raise_on_error(py, &compiled, instance), @@ -345,6 +343,7 @@ fn validate( /// If your workflow implies validating against the same schema, consider using `JSONSchema.iter_errors` /// instead. #[pyfunction] +#[allow(unused_variables)] #[pyo3(signature = (schema, instance, draft=None, with_meta_schemas=false, formats=None))] fn iter_errors( py: Python<'_>, @@ -354,7 +353,7 @@ fn iter_errors( with_meta_schemas: Option, formats: Option<&Bound<'_, PyDict>>, ) -> PyResult { - let options = make_options(draft, with_meta_schemas, formats)?; + let options = make_options(draft, formats)?; let schema = ser::to_value(schema)?; match options.compile(&schema) { Ok(compiled) => iter_on_error(py, &compiled, instance), @@ -403,6 +402,7 @@ fn handle_format_checked_panic(err: Box) -> PyErr { #[pymethods] impl JSONSchema { #[new] + #[allow(unused_variables)] #[pyo3(signature = (schema, draft=None, with_meta_schemas=false, formats=None))] fn new( py: Python<'_>, @@ -411,7 +411,7 @@ impl JSONSchema { with_meta_schemas: Option, formats: Option<&Bound<'_, PyDict>>, ) -> PyResult { - let options = make_options(draft, with_meta_schemas, formats)?; + let options = make_options(draft, formats)?; let raw_schema = ser::to_value(schema)?; match options.compile(&raw_schema) { Ok(schema) => Ok(JSONSchema { @@ -429,6 +429,7 @@ impl JSONSchema { /// /// Use it if you have your schema as a string and want to utilize Rust JSON parsing. #[classmethod] + #[allow(unused_variables)] #[pyo3(signature = (string, draft=None, with_meta_schemas=false, formats=None))] fn from_str( _: &Bound<'_, PyType>, @@ -453,7 +454,7 @@ impl JSONSchema { let slice = unsafe { std::slice::from_raw_parts(ptr.cast::(), str_size as usize) }; let raw_schema = serde_json::from_slice(slice) .map_err(|error| PyValueError::new_err(format!("Invalid string: {}", error)))?; - let options = make_options(draft, with_meta_schemas, formats)?; + let options = make_options(draft, formats)?; match options.compile(&raw_schema) { Ok(schema) => Ok(JSONSchema { schema, diff --git a/bindings/python/tests-py/test_suite.py b/bindings/python/tests-py/test_suite.py index 3fe4d5bc..e49310e5 100644 --- a/bindings/python/tests-py/test_suite.py +++ b/bindings/python/tests-py/test_suite.py @@ -92,7 +92,7 @@ def pytest_generate_tests(metafunc): def test_draft(filename, draft, schema, instance, expected, description): error_message = f"[{filename}] {description}: {schema} | {instance}" try: - result = jsonschema_rs.is_valid(schema, instance, int(draft), with_meta_schemas=True) + result = jsonschema_rs.is_valid(schema, instance, int(draft)) assert result is expected, error_message except ValueError: pytest.fail(error_message) diff --git a/jsonschema/benches/jsonschema.rs b/jsonschema/benches/jsonschema.rs index 548a01f5..2dd6e59f 100644 --- a/jsonschema/benches/jsonschema.rs +++ b/jsonschema/benches/jsonschema.rs @@ -8,13 +8,12 @@ use serde_json::Value; macro_rules! jsonschema_bench { ($c:tt, $name:expr, $schema:ident, $instance:ident) => {{ let compiled = JSONSchema::options() - .with_meta_schemas() .compile(&$schema) .expect("Invalid schema"); assert!(compiled.is_valid(&$instance), "Invalid instance"); assert!(compiled.validate(&$instance).is_ok(), "Invalid instance"); $c.bench_function(&format!("{} jsonschema/compile", $name), |b| { - b.iter(|| JSONSchema::options().with_meta_schemas().compile(&$schema)) + b.iter(|| JSONSchema::options().compile(&$schema)) }); $c.bench_function(&format!("{} jsonschema/is_valid", $name), |b| { b.iter(|| compiled.is_valid(&$instance)) diff --git a/jsonschema/src/compilation/options.rs b/jsonschema/src/compilation/options.rs index bd159b90..d638ee06 100644 --- a/jsonschema/src/compilation/options.rs +++ b/jsonschema/src/compilation/options.rs @@ -12,12 +12,13 @@ use crate::{ }; use ahash::AHashMap; use once_cell::sync::Lazy; -use std::{fmt, sync::Arc}; +use std::{borrow::Cow, fmt, sync::Arc}; macro_rules! schema { ($name:ident, $path:expr) => { - static $name: Lazy = - Lazy::new(|| serde_json::from_str(include_str!($path)).expect("Invalid schema")); + static $name: Lazy> = Lazy::new(|| { + Arc::new(serde_json::from_slice(include_bytes!($path)).expect("Invalid schema")) + }); }; } @@ -79,84 +80,84 @@ schema!( "../../meta_schemas/draft2020-12/meta/content.json" ); -static META_SCHEMAS: Lazy>> = Lazy::new(|| { +static META_SCHEMAS: Lazy, Arc>> = Lazy::new(|| { let mut store = AHashMap::with_capacity(3); store.insert( - "http://json-schema.org/draft-04/schema".to_string(), - Arc::new(DRAFT4.clone()), + "http://json-schema.org/draft-04/schema".into(), + Arc::clone(&DRAFT4), ); store.insert( - "http://json-schema.org/draft-06/schema".to_string(), - Arc::new(DRAFT6.clone()), + "http://json-schema.org/draft-06/schema".into(), + Arc::clone(&DRAFT6), ); store.insert( - "http://json-schema.org/draft-07/schema".to_string(), - Arc::new(DRAFT7.clone()), + "http://json-schema.org/draft-07/schema".into(), + Arc::clone(&DRAFT7), ); #[cfg(feature = "draft201909")] { store.insert( - "https://json-schema.org/draft/2019-09/schema".to_string(), - Arc::new(DRAFT201909.clone()), + "https://json-schema.org/draft/2019-09/schema".into(), + Arc::clone(&DRAFT201909), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/applicator".to_string(), - Arc::new(DRAFT201909_APPLICATOR.clone()), + "https://json-schema.org/draft/2019-09/meta/applicator".into(), + Arc::clone(&DRAFT201909_APPLICATOR), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/content".to_string(), - Arc::new(DRAFT201909_CONTENT.clone()), + "https://json-schema.org/draft/2019-09/meta/content".into(), + Arc::clone(&DRAFT201909_CONTENT), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/core".to_string(), - Arc::new(DRAFT201909_CORE.clone()), + "https://json-schema.org/draft/2019-09/meta/core".into(), + Arc::clone(&DRAFT201909_CORE), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/format".to_string(), - Arc::new(DRAFT201909_FORMAT.clone()), + "https://json-schema.org/draft/2019-09/meta/format".into(), + Arc::clone(&DRAFT201909_FORMAT), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/meta-data".to_string(), - Arc::new(DRAFT201909_META_DATA.clone()), + "https://json-schema.org/draft/2019-09/meta/meta-data".into(), + Arc::clone(&DRAFT201909_META_DATA), ); store.insert( - "https://json-schema.org/draft/2019-09/meta/validation".to_string(), - Arc::new(DRAFT201909_VALIDATION.clone()), + "https://json-schema.org/draft/2019-09/meta/validation".into(), + Arc::clone(&DRAFT201909_VALIDATION), ); } #[cfg(feature = "draft202012")] { store.insert( - "https://json-schema.org/draft/2020-12/schema".to_string(), - Arc::new(DRAFT202012.clone()), + "https://json-schema.org/draft/2020-12/schema".into(), + Arc::clone(&DRAFT202012), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/core".to_string(), - Arc::new(DRAFT202012_CORE.clone()), + "https://json-schema.org/draft/2020-12/meta/core".into(), + Arc::clone(&DRAFT202012_CORE), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/applicator".to_string(), - Arc::new(DRAFT202012_APPLICATOR.clone()), + "https://json-schema.org/draft/2020-12/meta/applicator".into(), + Arc::clone(&DRAFT202012_APPLICATOR), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/unevaluated".to_string(), - Arc::new(DRAFT202012_UNEVALUATED.clone()), + "https://json-schema.org/draft/2020-12/meta/unevaluated".into(), + Arc::clone(&DRAFT202012_UNEVALUATED), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/validation".to_string(), - Arc::new(DRAFT202012_VALIDATION.clone()), + "https://json-schema.org/draft/2020-12/meta/validation".into(), + Arc::clone(&DRAFT202012_VALIDATION), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/meta-data".to_string(), - Arc::new(DRAFT202012_META_DATA.clone()), + "https://json-schema.org/draft/2020-12/meta/meta-data".into(), + Arc::clone(&DRAFT202012_META_DATA), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/format-annotation".to_string(), - Arc::new(DRAFT202012_FORMAT_ANNOTATION.clone()), + "https://json-schema.org/draft/2020-12/meta/format-annotation".into(), + Arc::clone(&DRAFT202012_FORMAT_ANNOTATION), ); store.insert( - "https://json-schema.org/draft/2020-12/meta/content".to_string(), - Arc::new(DRAFT202012_CONTENT.clone()), + "https://json-schema.org/draft/2020-12/meta/content".into(), + Arc::clone(&DRAFT202012_CONTENT), ); } store @@ -187,77 +188,83 @@ static META_SCHEMA_VALIDATORS: Lazy> = Lazy .expect(EXPECT_MESSAGE), ); #[cfg(feature = "draft201909")] - store.insert( - schemas::Draft::Draft201909, - JSONSchema::options() - .without_schema_validation() - .with_document( - "https://json-schema.org/draft/2019-09/meta/applicator".to_string(), - DRAFT201909_APPLICATOR.clone(), - ) - .with_document( - "https://json-schema.org/draft/2019-09/meta/content".to_string(), - DRAFT201909_CONTENT.clone(), - ) - .with_document( - "https://json-schema.org/draft/2019-09/meta/core".to_string(), - DRAFT201909_CORE.clone(), - ) - .with_document( - "https://json-schema.org/draft/2019-09/meta/format".to_string(), - DRAFT201909_FORMAT.clone(), - ) - .with_document( - "https://json-schema.org/draft/2019-09/meta/meta-data".to_string(), - DRAFT201909_META_DATA.clone(), - ) - .with_document( - "https://json-schema.org/draft/2019-09/meta/validation".to_string(), - DRAFT201909_VALIDATION.clone(), - ) - .compile(&DRAFT201909) - .expect(EXPECT_MESSAGE), - ); + { + let mut options = JSONSchema::options(); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/applicator".into(), + Arc::clone(&DRAFT201909_APPLICATOR), + ); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/content".into(), + Arc::clone(&DRAFT201909_CONTENT), + ); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/core".into(), + Arc::clone(&DRAFT201909_CORE), + ); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/format".into(), + Arc::clone(&DRAFT201909_FORMAT), + ); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/meta-data".into(), + Arc::clone(&DRAFT201909_META_DATA), + ); + options.store.insert( + "https://json-schema.org/draft/2019-09/meta/validation".into(), + Arc::clone(&DRAFT201909_VALIDATION), + ); + store.insert( + schemas::Draft::Draft201909, + options + .without_schema_validation() + .compile(&DRAFT201909) + .expect(EXPECT_MESSAGE), + ); + } #[cfg(feature = "draft202012")] - store.insert( - schemas::Draft::Draft202012, - JSONSchema::options() - .without_schema_validation() - .with_document( - "https://json-schema.org/draft/2020-12/meta/applicator".to_string(), - DRAFT202012_APPLICATOR.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/core".to_string(), - DRAFT202012_CORE.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/applicator".to_string(), - DRAFT202012_APPLICATOR.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/unevaluated".to_string(), - DRAFT202012_UNEVALUATED.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/validation".to_string(), - DRAFT202012_VALIDATION.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/meta-data".to_string(), - DRAFT202012_META_DATA.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/format-annotation".to_string(), - DRAFT202012_FORMAT_ANNOTATION.clone(), - ) - .with_document( - "https://json-schema.org/draft/2020-12/meta/content".to_string(), - DRAFT202012_CONTENT.clone(), - ) - .compile(&DRAFT202012) - .expect(EXPECT_MESSAGE), - ); + { + let mut options = JSONSchema::options(); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/applicator".into(), + Arc::clone(&DRAFT202012_APPLICATOR), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/core".into(), + Arc::clone(&DRAFT202012_CORE), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/applicator".into(), + Arc::clone(&DRAFT202012_APPLICATOR), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/unevaluated".into(), + Arc::clone(&DRAFT202012_UNEVALUATED), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/validation".into(), + Arc::clone(&DRAFT202012_VALIDATION), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/meta-data".into(), + Arc::clone(&DRAFT202012_META_DATA), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/format-annotation".into(), + Arc::clone(&DRAFT202012_FORMAT_ANNOTATION), + ); + options.store.insert( + "https://json-schema.org/draft/2020-12/meta/content".into(), + Arc::clone(&DRAFT202012_CONTENT), + ); + store.insert( + schemas::Draft::Draft202012, + options + .without_schema_validation() + .compile(&DRAFT202012) + .expect(EXPECT_MESSAGE), + ) + }; store }); @@ -272,7 +279,7 @@ pub struct CompilationOptions { content_media_type_checks: AHashMap<&'static str, Option>, content_encoding_checks_and_converters: AHashMap<&'static str, Option<(ContentEncodingCheckType, ContentEncodingConverterType)>>, - store: AHashMap>, + store: AHashMap, Arc>, formats: AHashMap>, validate_formats: Option, validate_schema: bool, @@ -288,7 +295,7 @@ impl Default for CompilationOptions { draft: Option::default(), content_media_type_checks: AHashMap::default(), content_encoding_checks_and_converters: AHashMap::default(), - store: AHashMap::default(), + store: META_SCHEMAS.clone(), formats: AHashMap::default(), validate_formats: None, ignore_unknown_formats: true, @@ -561,8 +568,8 @@ impl CompilationOptions { /// /// The example above is taken from the Swagger 2.0 JSON schema. #[inline] + #[deprecated(since = "0.19.0", note = "Meta schemas are now included by default")] pub fn with_meta_schemas(&mut self) -> &mut Self { - self.store.extend(META_SCHEMAS.clone()); self } @@ -570,7 +577,7 @@ impl CompilationOptions { /// calls to remote schemas via the `$ref` keyword. #[inline] pub fn with_document(&mut self, id: String, document: serde_json::Value) -> &mut Self { - self.store.insert(id, Arc::new(document)); + self.store.insert(id.into(), Arc::new(document)); self } /// Register a custom "format" validator. diff --git a/jsonschema/src/keywords/ref_.rs b/jsonschema/src/keywords/ref_.rs index e3dcfb0c..bfb59b9e 100644 --- a/jsonschema/src/keywords/ref_.rs +++ b/jsonschema/src/keywords/ref_.rs @@ -6,6 +6,7 @@ use crate::{ primitive_type::PrimitiveType, resolver::Resolver, schema_node::SchemaNode, + schemas::draft_from_schema, validator::Validate, CompilationOptions, Draft, ValidationError, }; @@ -38,6 +39,16 @@ impl RefValidator { resolver: Arc::clone(&context.resolver), })) } + + fn get_config_for_resolved_schema(&self, resolved: &Value) -> Arc { + if let Some(draft) = draft_from_schema(resolved) { + let mut config = (*self.config).clone(); + config.with_draft(draft); + Arc::new(config) + } else { + Arc::clone(&self.config) + } + } } impl Validate for RefValidator { @@ -50,11 +61,8 @@ impl Validate for RefValidator { &self.reference, &self.original_reference, ) { - let context = CompilationContext::new( - scope.into(), - Arc::clone(&self.config), - Arc::clone(&self.resolver), - ); + let config = self.get_config_for_resolved_schema(&resolved); + let context = CompilationContext::new(scope.into(), config, Arc::clone(&self.resolver)); if let Ok(node) = compile_validators(&resolved, &context) { let result = node.is_valid(instance); *self.sub_nodes.write() = Some(node); @@ -88,11 +96,9 @@ impl Validate for RefValidator { &self.original_reference, ) { Ok((scope, resolved)) => { - let context = CompilationContext::new( - scope.into(), - Arc::clone(&self.config), - Arc::clone(&self.resolver), - ); + let config = self.get_config_for_resolved_schema(&resolved); + let context = + CompilationContext::new(scope.into(), config, Arc::clone(&self.resolver)); match compile_validators(&resolved, &context) { Ok(node) => { let result = Box::new( @@ -155,6 +161,72 @@ mod tests { use serde_json::{json, Value}; use test_case::test_case; + #[test_case( + &json!({ + "$ref": "http://json-schema.org/draft-04/schema#" + }), + &json!({ + "definitions": { + "foo": { + "type": "integer" + } + } + }) + )] + #[test_case( + &json!({ + "$ref": "http://json-schema.org/draft-06/schema#" + }), + &json!({ + "definitions": { + "foo": { + "type": "integer" + } + } + }) + )] + #[test_case( + &json!({ + "$ref": "http://json-schema.org/draft-07/schema#" + }), + &json!({ + "definitions": { + "foo": { + "type": "integer" + } + } + }) + )] + #[cfg_attr(feature = "draft201909", test_case( + &json!({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$ref": "https://json-schema.org/draft/2019-09/schema" + }), + &json!({ + "$defs": { + "foo": { + "type": "integer" + } + } + }) + ))] + #[cfg_attr(feature = "draft202012", test_case( + &json!({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "https://json-schema.org/draft/2020-12/schema" + }), + &json!({ + "$defs": { + "foo": { + "type": "integer" + } + } + }) + ))] + fn definition_against_metaschema(schema: &Value, instance: &Value) { + tests_util::is_valid(schema, instance); + } + #[test_case( &json!({ "properties": { diff --git a/jsonschema/src/lib.rs b/jsonschema/src/lib.rs index 603f3277..4b4045b2 100644 --- a/jsonschema/src/lib.rs +++ b/jsonschema/src/lib.rs @@ -178,16 +178,18 @@ pub(crate) mod tests_util { } fn is_valid_inner(compiled: &JSONSchema, instance: &Value) { + if let Err(mut errors) = compiled.validate(instance) { + let first = errors.next().expect("Errors iterator is empty"); + panic!( + "{} should be valid (via validate). Error: {} at {}", + instance, first, first.instance_path + ); + } 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)", diff --git a/jsonschema/src/resolver.rs b/jsonschema/src/resolver.rs index 7c813422..1c9e20e5 100644 --- a/jsonschema/src/resolver.rs +++ b/jsonschema/src/resolver.rs @@ -120,7 +120,7 @@ pub(crate) struct Resolver { // canonical_id is composed with the root document id // (if not specified, then `DEFAULT_ROOT_URL` is used for this purpose) schemas: AHashMap>, - store: RwLock>>, + store: RwLock, Arc>>, } impl std::fmt::Debug for Resolver { @@ -139,7 +139,7 @@ impl Resolver { draft: Draft, scope: &Url, schema: Arc, - store: AHashMap>, + store: AHashMap, Arc>, ) -> Result> { let mut schemas: AHashMap> = AHashMap::new(); // traverse the schema and store all named ones under their canonical ids @@ -175,7 +175,7 @@ impl Resolver { .map_err(|error| ValidationError::resolver(url.clone(), error))?; self.store .write() - .insert(url.clone().into(), resolved.clone()); + .insert(url.to_string().into(), resolved.clone()); Ok(resolved) } }, diff --git a/jsonschema/tests/test_suite.rs b/jsonschema/tests/test_suite.rs index c17e7eca..004cf041 100644 --- a/jsonschema/tests/test_suite.rs +++ b/jsonschema/tests/test_suite.rs @@ -82,7 +82,6 @@ fn test_draft(_server_address: &str, test_case: TestCase) { let compiled = JSONSchema::options() .with_draft(draft_version) - .with_meta_schemas() .should_validate_formats(true) .compile(&test_case.schema) .expect("should not fail to compile schema"); @@ -175,7 +174,6 @@ fn test_instance_path() { let suite_id = item["suite_id"].as_u64().expect("Is integer") as usize; let raw_schema = &data[suite_id]["schema"]; let schema = JSONSchema::options() - .with_meta_schemas() .compile(raw_schema) .unwrap_or_else(|_| { panic!(