parent
51d71ceb6d
commit
509c14c7a0
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Number comparison for `enum` and `const` keywords. [#149](https://github.com/Stranger6667/jsonschema-rs/issues/149)
|
||||
|
||||
### Performance
|
||||
|
||||
- Some performance related changes were rolled back, due to increased complexity.
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Number comparison for `enum` and `const` keywords. [#149](https://github.com/Stranger6667/jsonschema-rs/issues/149)
|
||||
|
||||
## [0.4.1] - 2020-12-09
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::keywords::helpers;
|
||||
use crate::{
|
||||
compilation::{context::CompilationContext, JSONSchema},
|
||||
error::{error, no_error, ErrorIterator, ValidationError},
|
||||
|
@ -31,7 +32,7 @@ impl Validate for ConstArrayValidator {
|
|||
#[inline]
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
if let Value::Array(instance_value) = instance {
|
||||
&self.value == instance_value
|
||||
helpers::equal_arrays(&self.value, instance_value)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -181,7 +182,7 @@ impl Validate for ConstObjectValidator {
|
|||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
if let Value::Object(item) = instance {
|
||||
&self.value == item
|
||||
helpers::equal_objects(&self.value, item)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -27,10 +27,6 @@ impl EnumValidator {
|
|||
}
|
||||
|
||||
impl Validate for EnumValidator {
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
self.items.iter().any(|item| helpers::equal(instance, item))
|
||||
}
|
||||
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
error(ValidationError::enumeration(instance, &self.options))
|
||||
|
@ -38,6 +34,10 @@ impl Validate for EnumValidator {
|
|||
no_error()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
self.items.iter().any(|item| helpers::equal(instance, item))
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for EnumValidator {
|
||||
|
|
|
@ -1,8 +1,47 @@
|
|||
use serde_json::Value;
|
||||
use num_cmp::NumCmp;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
macro_rules! num_cmp {
|
||||
($left:expr, $right:expr) => {
|
||||
if let Some(b) = $right.as_u64() {
|
||||
NumCmp::num_eq($left, b)
|
||||
} else if let Some(b) = $right.as_i64() {
|
||||
NumCmp::num_eq($left, b)
|
||||
} else {
|
||||
NumCmp::num_eq($left, $right.as_f64().expect("Always valid"))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn equal(left: &Value, right: &Value) -> bool {
|
||||
match (left, right) {
|
||||
(Value::Number(left), Value::Number(right)) => left.as_f64() == right.as_f64(),
|
||||
(Value::Number(left), Value::Number(right)) => {
|
||||
if let Some(a) = left.as_u64() {
|
||||
num_cmp!(a, right)
|
||||
} else if let Some(a) = left.as_i64() {
|
||||
num_cmp!(a, right)
|
||||
} else {
|
||||
let a = left.as_f64().expect("Always valid");
|
||||
num_cmp!(a, right)
|
||||
}
|
||||
}
|
||||
(Value::Array(left), Value::Array(right)) => equal_arrays(left, right),
|
||||
(Value::Object(left), Value::Object(right)) => equal_objects(left, right),
|
||||
(_, _) => left == right,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn equal_arrays(left: &[Value], right: &[Value]) -> bool {
|
||||
left.len() == right.len() && left.iter().zip(right.iter()).all(|(a, b)| equal(a, b))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn equal_objects(left: &Map<String, Value>, right: &Map<String, Value>) -> bool {
|
||||
left.len() == right.len()
|
||||
&& left
|
||||
.iter()
|
||||
.zip(right)
|
||||
.all(|((ka, va), (kb, vb))| ka == kb && equal(va, vb))
|
||||
}
|
||||
|
|
|
@ -254,4 +254,29 @@ mod tests {
|
|||
let compiled = JSONSchema::compile(schema).unwrap();
|
||||
assert!(compiled.is_valid(instance))
|
||||
}
|
||||
// enum: Number
|
||||
#[test_case(&json!({"enum": [0.0]}), &json!(0))]
|
||||
// enum: Array
|
||||
#[test_case(&json!({"enum": [[1.0]]}), &json!([1]))]
|
||||
// enum: Object
|
||||
#[test_case(&json!({"enum": [{"a": 1.0}]}), &json!({"a": 1}))]
|
||||
// enum:: Object in Array
|
||||
#[test_case(&json!({"enum": [[{"b": 1.0}]]}), &json!([{"b": 1}]))]
|
||||
// enum:: Array in Object
|
||||
#[test_case(&json!({"enum": [{"c": [1.0]}]}), &json!({"c": [1]}))]
|
||||
// const: Number
|
||||
#[test_case(&json!({"const": 0.0}), &json!(0))]
|
||||
// const: Array
|
||||
#[test_case(&json!({"const": [1.0]}), &json!([1]))]
|
||||
// const: Object
|
||||
#[test_case(&json!({"const": {"a": 1.0}}), &json!({"a": 1}))]
|
||||
// const:: Object in Array
|
||||
#[test_case(&json!({"const": [{"b": 1.0}]}), &json!([{"b": 1}]))]
|
||||
// const:: Array in Object
|
||||
#[test_case(&json!({"const": {"c": [1.0]}}), &json!({"c": [1]}))]
|
||||
fn numeric_equivalence(schema: &Value, instance: &Value) {
|
||||
// Regression: https://github.com/Stranger6667/jsonschema-rs/issues/149
|
||||
let compiled = JSONSchema::compile(schema).unwrap();
|
||||
assert!(compiled.is_valid(instance))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue