diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml index 7b1aadfd..c53ff20c 100644 --- a/schemars/Cargo.toml +++ b/schemars/Cargo.toml @@ -37,7 +37,7 @@ uuid1 = { version = "1.0", default-features = false, optional = true, package = pretty_assertions = "1.2.1" trybuild = "1.0" serde = { version = "1.0", features = ["derive"] } -jsonschema = { version = "0.18.1", default-features = false } +jsonschema = { version = "0.18.1", default-features = false, features = ["draft201909", "draft202012"] } snapbox = { version = "0.6.17", features = ["json"] } arrayvec07 = { version = "0.7", default-features = false, features = ["serde"], package = "arrayvec"} diff --git a/schemars/tests/enum_flatten.rs b/schemars/tests/enum_flatten.rs deleted file mode 100644 index 4c94a4c5..00000000 --- a/schemars/tests/enum_flatten.rs +++ /dev/null @@ -1,89 +0,0 @@ -mod util; -use schemars::{generate::SchemaSettings, JsonSchema}; -use util::*; - -#[allow(dead_code)] -#[derive(JsonSchema)] -struct Flat { - f: f32, - #[schemars(flatten)] - e1: Enum1, - #[schemars(flatten)] - e2: Enum2, - #[schemars(flatten)] - e3: Enum3, - #[schemars(flatten)] - e4: Enum4, - #[schemars(flatten)] - e5: Enum5, -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -enum Enum1 { - B(bool), - S(String), -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -enum Enum2 { - U(u32), - F(f64), -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -enum Enum3 { - B2(bool), - S2(String), -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -enum Enum4 { - U2(u32), - F2(f64), -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -enum Enum5 { - B3(bool), - S3(String), -} - -#[test] -fn test_flat_schema() -> TestResult { - test_default_generated_schema::("enum_flatten") -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(deny_unknown_fields)] -struct FlatDenyUnknownFields { - f: f32, - #[schemars(flatten)] - e1: Enum1, - #[schemars(flatten)] - e2: Enum2, - #[schemars(flatten)] - e3: Enum3, - #[schemars(flatten)] - e4: Enum4, - #[schemars(flatten)] - e5: Enum5, -} - -#[test] -fn test_flat_schema_duf() -> TestResult { - test_default_generated_schema::("enum_flatten_duf") -} - -#[test] -fn test_flat_schema_duf_draft07() -> TestResult { - test_generated_schema::( - "enum_flatten_duf_draft07", - SchemaSettings::draft07(), - ) -} diff --git a/schemars/tests/integration/enums_deny_unknown_fields.rs b/schemars/tests/integration/enums_deny_unknown_fields.rs index eb1de3ca..9eb79bfb 100644 --- a/schemars/tests/integration/enums_deny_unknown_fields.rs +++ b/schemars/tests/integration/enums_deny_unknown_fields.rs @@ -1,6 +1,28 @@ +use crate::prelude::*; use std::collections::BTreeMap; -use crate::prelude::*; +macro_rules! fn_values { + () => { + fn values() -> impl IntoIterator { + [ + Self::Unit, + Self::StringMap( + [("hello".to_owned(), "world".to_owned())] + .into_iter() + .collect(), + ), + Self::StructNewType(Struct { + foo: 123, + bar: true, + }), + Self::Struct { + foo: 123, + bar: true, + }, + ] + } + }; +} #[derive(JsonSchema, Deserialize, Serialize, Default)] struct Struct { @@ -18,24 +40,7 @@ enum External { } impl External { - fn values() -> impl IntoIterator { - [ - Self::Unit, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - ] - } + fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] @@ -48,24 +53,7 @@ enum Internal { } impl Internal { - fn values() -> impl IntoIterator { - [ - Self::Unit, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - ] - } + fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] @@ -78,24 +66,7 @@ enum Adjacent { } impl Adjacent { - fn values() -> impl IntoIterator { - [ - Self::Unit, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - ] - } + fn_values!(); } #[derive(JsonSchema, Deserialize, Serialize)] @@ -108,24 +79,7 @@ enum Untagged { } impl Untagged { - fn values() -> impl IntoIterator { - [ - Self::Unit, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - ] - } + fn_values!(); } #[test] diff --git a/schemars/tests/integration/enums_flattened.rs b/schemars/tests/integration/enums_flattened.rs new file mode 100644 index 00000000..930fe47f --- /dev/null +++ b/schemars/tests/integration/enums_flattened.rs @@ -0,0 +1,136 @@ +use schemars::generate::SchemaSettings; + +use crate::prelude::*; + +macro_rules! fn_values { + () => { + fn values() -> impl IntoIterator { + [ + Self { + f: 1.23, + e1: Enum1::B(true), + e2: Enum2::F(4.56), + e3: Enum3::S2("abc".into()), + e4: Enum4::U2(789), + e5: Enum5::B3(false), + }, + Self { + f: 9.87, + e1: Enum1::S("def".into()), + e2: Enum2::U(654), + e3: Enum3::B2(true), + e4: Enum4::F2(3.21), + e5: Enum5::S3("ghi".into()), + }, + ] + } + }; +} + +#[derive(JsonSchema, Deserialize, Serialize)] +enum Enum1 { + B(bool), + S(String), +} + +#[derive(JsonSchema, Deserialize, Serialize)] +enum Enum2 { + U(u32), + F(f64), +} + +#[derive(JsonSchema, Deserialize, Serialize)] +enum Enum3 { + B2(bool), + S2(String), +} + +#[derive(JsonSchema, Deserialize, Serialize)] +enum Enum4 { + U2(u32), + F2(f64), +} + +#[derive(JsonSchema, Deserialize, Serialize)] +enum Enum5 { + B3(bool), + S3(String), +} + +#[derive(JsonSchema, Deserialize, Serialize)] +struct Container { + f: f32, + #[serde(flatten)] + e1: Enum1, + #[serde(flatten)] + e2: Enum2, + #[serde(flatten)] + e3: Enum3, + #[serde(flatten)] + e4: Enum4, + #[serde(flatten)] + e5: Enum5, +} + +impl Container { + fn_values!(); +} + +#[derive(JsonSchema, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +struct ContainerDenyUnknownFields { + f: f32, + #[serde(flatten)] + e1: Enum1, + #[serde(flatten)] + e2: Enum2, + #[serde(flatten)] + e3: Enum3, + #[serde(flatten)] + e4: Enum4, + #[serde(flatten)] + e5: Enum5, +} + +impl ContainerDenyUnknownFields { + fn_values!(); +} + +fn json_with_extra_field() -> Value { + json!({ + "f": 1.23, + "B": true, + "F": 4.56, + "S2": "abc", + "U2": 789, + "B3": false, + "extra": null + }) +} + +#[test] +fn enums_flattened() { + test!(Container) + .assert_snapshot() + .assert_allows_ser_roundtrip(Container::values()) + .assert_matches_de_roundtrip(arbitrary_values()) + .assert_allows_de_roundtrip([json_with_extra_field()]); +} + +#[test] +fn enums_flattened_deny_unknown_fields() { + test!(ContainerDenyUnknownFields) + .assert_snapshot() + .assert_allows_ser_roundtrip(ContainerDenyUnknownFields::values()) + .assert_matches_de_roundtrip(arbitrary_values()) + .assert_rejects_de([json_with_extra_field()]); +} + +#[test] +fn enums_flattened_deny_unknown_fields_draft07() { + test!(ContainerDenyUnknownFields, SchemaSettings::draft07()) + .assert_snapshot() + .assert_allows_ser_roundtrip(ContainerDenyUnknownFields::values()) + .assert_matches_de_roundtrip(arbitrary_values()) + .assert_rejects_de([json_with_extra_field()]); +} diff --git a/schemars/tests/integration/main.rs b/schemars/tests/integration/main.rs index 2cfded98..365fc457 100644 --- a/schemars/tests/integration/main.rs +++ b/schemars/tests/integration/main.rs @@ -19,6 +19,7 @@ mod either; mod enum_repr; mod enums; mod enums_deny_unknown_fields; +mod enums_flattened; mod prelude { pub use crate::test; @@ -32,7 +33,7 @@ mod test_helper; #[macro_export] macro_rules! test { - ($type:ty) => { + ($type:ty, $settings:expr) => { $crate::test_helper::TestHelper::<$type>::new( { fn f() {} @@ -47,7 +48,10 @@ macro_rules! test { format!("{}~{}", core::file!(), test_name) }, - schemars::generate::SchemaSettings::default(), + $settings, ) }; + ($type:ty) => { + test!($type, schemars::generate::SchemaSettings::default()) + }; } diff --git a/schemars/tests/expected/enum_flatten.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.de.json similarity index 99% rename from schemars/tests/expected/enum_flatten.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.de.json index dffd89e1..7df8b883 100644 --- a/schemars/tests/expected/enum_flatten.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.de.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Flat", + "title": "Container", "type": "object", "properties": { "f": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.ser.json new file mode 100644 index 00000000..7df8b883 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.ser.json @@ -0,0 +1,150 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Container", + "type": "object", + "properties": { + "f": { + "type": "number", + "format": "float" + } + }, + "required": [ + "f" + ], + "allOf": [ + { + "oneOf": [ + { + "type": "object", + "properties": { + "B": { + "type": "boolean" + } + }, + "required": [ + "B" + ] + }, + { + "type": "object", + "properties": { + "S": { + "type": "string" + } + }, + "required": [ + "S" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U" + ] + }, + { + "type": "object", + "properties": { + "F": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "B2": { + "type": "boolean" + } + }, + "required": [ + "B2" + ] + }, + { + "type": "object", + "properties": { + "S2": { + "type": "string" + } + }, + "required": [ + "S2" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U2": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U2" + ] + }, + { + "type": "object", + "properties": { + "F2": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F2" + ] + } + ] + } + ], + "oneOf": [ + { + "type": "object", + "properties": { + "B3": { + "type": "boolean" + } + }, + "required": [ + "B3" + ] + }, + { + "type": "object", + "properties": { + "S3": { + "type": "string" + } + }, + "required": [ + "S3" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/enum_flatten_duf.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.de.json similarity index 98% rename from schemars/tests/expected/enum_flatten_duf.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.de.json index 37493cc5..2032360d 100644 --- a/schemars/tests/expected/enum_flatten_duf.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.de.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "FlatDenyUnknownFields", + "title": "ContainerDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.ser.json new file mode 100644 index 00000000..2032360d --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.ser.json @@ -0,0 +1,151 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ContainerDenyUnknownFields", + "type": "object", + "properties": { + "f": { + "type": "number", + "format": "float" + } + }, + "required": [ + "f" + ], + "unevaluatedProperties": false, + "allOf": [ + { + "oneOf": [ + { + "type": "object", + "properties": { + "B": { + "type": "boolean" + } + }, + "required": [ + "B" + ] + }, + { + "type": "object", + "properties": { + "S": { + "type": "string" + } + }, + "required": [ + "S" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U" + ] + }, + { + "type": "object", + "properties": { + "F": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "B2": { + "type": "boolean" + } + }, + "required": [ + "B2" + ] + }, + { + "type": "object", + "properties": { + "S2": { + "type": "string" + } + }, + "required": [ + "S2" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U2": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U2" + ] + }, + { + "type": "object", + "properties": { + "F2": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F2" + ] + } + ] + } + ], + "oneOf": [ + { + "type": "object", + "properties": { + "B3": { + "type": "boolean" + } + }, + "required": [ + "B3" + ] + }, + { + "type": "object", + "properties": { + "S3": { + "type": "string" + } + }, + "required": [ + "S3" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/enum_flatten_duf_draft07.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.de.json similarity index 98% rename from schemars/tests/expected/enum_flatten_duf_draft07.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.de.json index 62323ddf..695f282d 100644 --- a/schemars/tests/expected/enum_flatten_duf_draft07.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.de.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "FlatDenyUnknownFields", + "title": "ContainerDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.ser.json new file mode 100644 index 00000000..695f282d --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.ser.json @@ -0,0 +1,161 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ContainerDenyUnknownFields", + "type": "object", + "properties": { + "f": { + "type": "number", + "format": "float" + }, + "B": true, + "B2": true, + "B3": true, + "F": true, + "F2": true, + "S": true, + "S2": true, + "S3": true, + "U": true, + "U2": true + }, + "required": [ + "f" + ], + "allOf": [ + { + "oneOf": [ + { + "type": "object", + "properties": { + "B": { + "type": "boolean" + } + }, + "required": [ + "B" + ] + }, + { + "type": "object", + "properties": { + "S": { + "type": "string" + } + }, + "required": [ + "S" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U" + ] + }, + { + "type": "object", + "properties": { + "F": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "B2": { + "type": "boolean" + } + }, + "required": [ + "B2" + ] + }, + { + "type": "object", + "properties": { + "S2": { + "type": "string" + } + }, + "required": [ + "S2" + ] + } + ] + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "U2": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "U2" + ] + }, + { + "type": "object", + "properties": { + "F2": { + "type": "number", + "format": "double" + } + }, + "required": [ + "F2" + ] + } + ] + } + ], + "oneOf": [ + { + "type": "object", + "properties": { + "B3": { + "type": "boolean" + } + }, + "required": [ + "B3" + ] + }, + { + "type": "object", + "properties": { + "S3": { + "type": "string" + } + }, + "required": [ + "S3" + ] + } + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/schemars/tests/integration/test_helper.rs b/schemars/tests/integration/test_helper.rs index 19ccf0b6..15d0a59a 100644 --- a/schemars/tests/integration/test_helper.rs +++ b/schemars/tests/integration/test_helper.rs @@ -110,41 +110,60 @@ impl TestHelper { .get_or_init(|| self.schema_for::(Contract::Serialize)) } - fn de_schema_compiled(&self) -> &CompiledSchema { - self.de_schema_compiled.get_or_init(|| { - CompiledSchema::compile(self.de_schema().as_value()).expect("valid deserialize schema") - }) + fn de_schema_validate(&self, instance: &Value) -> bool { + self.de_schema_compiled + .get_or_init(|| compile_schema(self.de_schema())) + // Can't use `.validate(instance)` due to https://github.com/Stranger6667/jsonschema-rs/issues/496 + .validate(instance) + .is_ok() } - fn ser_schema_compiled(&self) -> &CompiledSchema { - self.ser_schema_compiled.get_or_init(|| { - CompiledSchema::compile(self.ser_schema().as_value()).expect("valid serialize schema") - }) + fn ser_schema_validate(&self, instance: &Value) -> bool { + self.ser_schema_compiled + .get_or_init(|| compile_schema(self.ser_schema())) + // Can't use `.validate(instance)` due to https://github.com/Stranger6667/jsonschema-rs/issues/496 + .validate(instance) + .is_ok() } } +fn compile_schema(schema: &Schema) -> CompiledSchema { + use jsonschema::Draft; + + let meta_schema = schema.get("$schema").and_then(Value::as_str).unwrap_or(""); + let mut options = CompiledSchema::options(); + options.should_validate_formats(true); + + if meta_schema.contains("draft-07") { + options.with_draft(Draft::Draft7); + } else if meta_schema.contains("2019-09") { + options.with_draft(Draft::Draft201909); + } else if meta_schema.contains("2020-12") { + options.with_draft(Draft::Draft202012); + }; + + options.compile(schema.as_value()).expect("valid schema") +} + impl Deserialize<'de>> TestHelper { /// Checks that the "serialize" schema allows the given sample values when serialized to JSON /// and, if the value can then be deserialized, that the "deserialize" schema also allows it. pub fn assert_allows_ser_roundtrip(&self, samples: impl IntoIterator) -> &Self { - let ser_schema = self.ser_schema_compiled(); - let de_schema = self.de_schema_compiled(); - for sample in samples { let json = serde_json::to_value(sample).unwrap(); assert!( - ser_schema.is_valid(&json), + self.ser_schema_validate(&json), "serialize schema should allow serialized value: {json}" ); if T::deserialize(&json).is_ok() { assert!( - de_schema.is_valid(&json), + self.de_schema_validate(&json), "deserialize schema should allow value accepted by deserialization: {json}" ); } else { assert!( - !de_schema.is_valid(&json), + !self.de_schema_validate(&json), "deserialize schema should reject undeserializable value: {json}" ); } @@ -163,9 +182,6 @@ impl Deserialize<'de>> TestHelper { &self, samples: impl IntoIterator>, ) -> &Self { - let ser_schema = self.ser_schema_compiled(); - let de_schema = self.de_schema_compiled(); - for sample in samples { let sample = sample.borrow(); let Ok(deserialized) = T::deserialize(sample) else { @@ -176,13 +192,13 @@ impl Deserialize<'de>> TestHelper { }; assert!( - de_schema.is_valid(sample), + self.de_schema_validate(sample), "deserialize schema should allow value accepted by deserialization: {sample}" ); if let Ok(serialized) = serde_json::to_value(&deserialized) { assert!( - ser_schema.is_valid(&serialized), + self.ser_schema_validate(&serialized), "serialize schema should allow serialized value: {serialized}" ); } @@ -200,29 +216,26 @@ impl Deserialize<'de>> TestHelper { &self, samples: impl IntoIterator>, ) -> &Self { - let ser_schema = self.ser_schema_compiled(); - let de_schema = self.de_schema_compiled(); - for value in samples { let value = value.borrow(); match T::deserialize(value) { Ok(deserialized) => { assert!( - de_schema.is_valid(value), + self.de_schema_validate(value), "deserialize schema should allow value accepted by deserialization: {value}" ); if let Ok(serialized) = serde_json::to_value(&deserialized) { assert!( - ser_schema.is_valid(&serialized), + self.ser_schema_validate(&serialized), "serialize schema should allow serialized value: {serialized}" ); } } Err(_) => { assert!( - !de_schema.is_valid(value), + !self.de_schema_validate(value), "deserialize schema should reject invalid value: {value}" ); @@ -230,7 +243,7 @@ impl Deserialize<'de>> TestHelper { // odd (though not necessarily wrong) for it to fail. If this does ever fail // a case that should be legitimate, then this assert can be removed/weakened. assert!( - !ser_schema.is_valid(value), + !self.ser_schema_validate(value), "serialize schema should reject invalid value: {value}" ); } @@ -246,8 +259,6 @@ impl Deserialize<'de>> TestHelper { /// has the advantage that it also verifies that the test case itself is actually covering the /// failure case as intended. pub fn assert_rejects_de(&self, values: impl IntoIterator>) -> &Self { - let de_schema = self.de_schema_compiled(); - for value in values { let value = value.borrow(); @@ -258,7 +269,7 @@ impl Deserialize<'de>> TestHelper { ); assert!( - !de_schema.is_valid(value), + !self.de_schema_validate(value), "deserialize schema should reject invalid value: {value}" ); }