From 7ef11550e592342b21edb78e3afeb894f347fa20 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Fri, 13 Sep 2024 22:40:16 +0200 Subject: [PATCH] fix: Combination of `unevaluatedProperties` with `allOf` and `oneOf` Ref: #496 Signed-off-by: Dmitry Dygalo --- CHANGELOG.md | 1 + crates/jsonschema-py/CHANGELOG.md | 1 + .../src/keywords/unevaluated_properties.rs | 53 ++++++++++++++++--- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9474b2b..16220761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### Fixed - `uuid` format validation. +- Combination of `unevaluatedProperties` with `allOf` and `oneOf`. [#496](https://github.com/Stranger6667/jsonschema-rs/issues/496) ### Deprecated diff --git a/crates/jsonschema-py/CHANGELOG.md b/crates/jsonschema-py/CHANGELOG.md index 00a3d1c2..8b6ceaa0 100644 --- a/crates/jsonschema-py/CHANGELOG.md +++ b/crates/jsonschema-py/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - `uuid` format validation. +- Combination of `unevaluatedProperties` with `allOf` and `oneOf`. [#496](https://github.com/Stranger6667/jsonschema-rs/issues/496) ### Performance diff --git a/crates/jsonschema/src/keywords/unevaluated_properties.rs b/crates/jsonschema/src/keywords/unevaluated_properties.rs index 5eb983a0..49fe2e8a 100644 --- a/crates/jsonschema/src/keywords/unevaluated_properties.rs +++ b/crates/jsonschema/src/keywords/unevaluated_properties.rs @@ -313,7 +313,7 @@ impl UnevaluatedPropertiesValidator { }) }) .or_else(|| { - let result = self.subschemas.as_ref().and_then(|subschemas| { + self.subschemas.as_ref().and_then(|subschemas| { subschemas.iter().find_map(|subschema| { subschema.apply_property( instance, @@ -323,9 +323,7 @@ impl UnevaluatedPropertiesValidator { property_name, ) }) - }); - - result + }) }) .or_else(|| { self.additional.as_ref().and_then(|additional| { @@ -649,14 +647,16 @@ impl SubschemaSubvalidator { let results = mapped.collect::>(); let all_subschemas_valid = results.iter().all(|(_, instance_valid)| *instance_valid); - all_subschemas_valid.then(|| { + if all_subschemas_valid { // We only need to find the first valid evaluation because we know if that // all subschemas were valid against the instance that there can't actually // be any subschemas where the property was evaluated but invalid. results .iter() - .any(|(property_result, _)| matches!(property_result, Some(true))) - }) + .find_map(|(property_result, _)| *property_result) + } else { + None + } } // The instance must be valid against only _one_ subschema, and for that subschema, the @@ -1430,4 +1430,43 @@ mod tests { &json!({ "foo": "wee", "another": false }), ); } + + #[test] + fn test_unevaluated_properties_with_allof_oneof() { + let schema = json!({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "allOf": [{}], + "oneOf": [ + { + "properties": { + "blah": true + } + } + ], + "unevaluatedProperties": false + }); + + let valid = json!({ + "blah": 1 + }); + + let validator = crate::compile(&schema).expect("Schema should compile"); + + assert!(validator.validate(&valid).is_ok(), "Validation should pass"); + assert!(validator.is_valid(&valid), "Instance should be valid"); + + let invalid = json!({ + "blah": 1, + "extra": "property" + }); + + assert!( + !validator.is_valid(&invalid), + "Instance with extra property should be invalid" + ); + assert!( + validator.validate(&invalid).is_err(), + "Validation should fail for instance with extra property" + ); + } }