feat: Add option to disable processing the `format` keyword

Prior to draft versions 2019-09, format validation is enabled by default
(though should be able to be disabled), and vice versa afterword.
This patch adds `should_validate_formats` to CompilationOptions to force
the option one way or another.

If not specified, it will fallback to a default based on the draft
version (enabled by default before draft 2019-09).

Closes #261
This commit is contained in:
Jacob Mischka 2021-10-02 12:57:38 -05:00 committed by Dmitry Dygalo
parent 86bb87fa66
commit aaadd99b2c
5 changed files with 53 additions and 0 deletions

View File

@ -7,6 +7,7 @@
- `uuid` format validator. [#266](https://github.com/Stranger6667/jsonschema-rs/issues/266)
- `duration` format validator. [#265](https://github.com/Stranger6667/jsonschema-rs/issues/265)
- Collect annotations whilst evaulating schemas.[#262](https://github.com/Stranger6667/jsonschema-rs/issues/262)
- Option to turn off processing of the `format` keyword. [#261](https://github.com/Stranger6667/jsonschema-rs/issues/261)
- `basic` & `flag` output formatting styles. [#100](https://github.com/Stranger6667/jsonschema-rs/issues/100)
### Changed

View File

@ -135,6 +135,7 @@ pub struct CompilationOptions {
AHashMap<&'static str, Option<(ContentEncodingCheckType, ContentEncodingConverterType)>>,
store: AHashMap<String, Arc<serde_json::Value>>,
formats: AHashMap<&'static str, fn(&str) -> bool>,
validate_formats: Option<bool>,
validate_schema: bool,
}
@ -147,6 +148,7 @@ impl Default for CompilationOptions {
content_encoding_checks_and_converters: AHashMap::default(),
store: AHashMap::default(),
formats: AHashMap::default(),
validate_formats: None,
}
}
}
@ -460,6 +462,18 @@ impl CompilationOptions {
self.validate_schema = false;
self
}
#[inline]
/// Force enable or disable format validation.
/// The default behavior is dependent on draft version, but the default behavior can be
/// overridden to validate or not regardless of draft.
pub fn should_validate_formats(&mut self, validate_formats: bool) -> &mut Self {
self.validate_formats = Some(validate_formats);
self
}
pub(crate) fn validate_formats(&self) -> bool {
self.validate_formats
.unwrap_or_else(|| self.draft().validate_formats_by_default())
}
}
// format name & a pointer to a check function
type FormatKV<'a> = Option<(&'a &'static str, &'a fn(&str) -> bool)>;

View File

@ -414,6 +414,10 @@ pub(crate) fn compile<'a>(
schema: &'a Value,
context: &CompilationContext,
) -> Option<CompilationResult<'a>> {
if !context.config.validate_formats() {
return None;
}
if let Value::String(format) = schema {
if let Some((format, func)) = context.config.format(format) {
return Some(CustomFormatValidator::compile(context, format, *func));
@ -503,6 +507,27 @@ mod tests {
assert!(compiled.is_valid(&instance))
}
#[test]
fn format_validation() {
let schema = json!({"format": "email", "type": "string"});
let email_instance = json!("email@example.com");
let not_email_instance = json!("foo");
let with_validation = JSONSchema::options()
.should_validate_formats(true)
.compile(&schema)
.unwrap();
let without_validation = JSONSchema::options()
.should_validate_formats(false)
.compile(&schema)
.unwrap();
assert!(with_validation.is_valid(&email_instance));
assert!(!with_validation.is_valid(&not_email_instance));
assert!(without_validation.is_valid(&email_instance));
assert!(without_validation.is_valid(&not_email_instance));
}
#[test]
fn ecma_regex() {
// See GH-230
@ -526,6 +551,7 @@ mod tests {
let compiled = JSONSchema::options()
.with_draft(Draft201909)
.should_validate_formats(true)
.compile(&schema)
.unwrap();
@ -553,6 +579,7 @@ mod tests {
let compiled = JSONSchema::options()
.with_draft(Draft201909)
.should_validate_formats(true)
.compile(&schema)
.unwrap();

View File

@ -22,6 +22,16 @@ impl Default for Draft {
}
}
impl Draft {
pub(crate) const fn validate_formats_by_default(self) -> bool {
match self {
Draft::Draft4 | Draft::Draft6 | Draft::Draft7 => true,
#[cfg(feature = "draft201909")]
Draft::Draft201909 => false,
}
}
}
type CompileFunc<'a> = fn(
&'a Map<String, Value>,
&'a Value,

View File

@ -51,6 +51,7 @@ 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)
.unwrap();