#![allow(
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::shadow_unrelated,
clippy::semicolon_if_nothing_returned,
clippy::pattern_type_mismatch,
clippy::assertions_on_result_states,
clippy::as_conversions
)]
use super::super::*;
use crate::{format, vec};
use serde_json::json;
#[test]
fn test_deserialize_any() {
let schema = json!({
"type": "any",
"description": "any type",
"default": 42
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Any {
description,
default,
} => {
assert_eq!(description.as_deref(), Some("any type"));
assert_eq!(default, &Some(Value::from(42)));
}
_ => panic!("Expected Type::Any"),
}
}
#[test]
fn test_deserialize_integer_all_fields() {
let schema = json!({
"type": "integer",
"description": "an integer",
"minimum": 1,
"maximum": 10,
"default": 5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("an integer"));
assert_eq!(minimum, &Some(1));
assert_eq!(maximum, &Some(10));
assert_eq!(default, &Some(Value::from(5)));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_no_minimum() {
let schema = json!({
"type": "integer",
"description": "no min",
"maximum": 100,
"default": 50
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("no min"));
assert_eq!(minimum, &None);
assert_eq!(maximum, &Some(100));
assert_eq!(default, &Some(Value::from(50)));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_no_maximum() {
let schema = json!({
"type": "integer",
"description": "no max",
"minimum": -10,
"default": 0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("no max"));
assert_eq!(minimum, &Some(-10));
assert_eq!(maximum, &None);
assert_eq!(default, &Some(Value::from(0)));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_only_required() {
let schema = json!({
"type": "integer"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description, &None);
assert_eq!(minimum, &None);
assert_eq!(maximum, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_minimum_equals_maximum() {
let schema = json!({
"type": "integer",
"minimum": 5,
"maximum": 5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(5));
assert_eq!(maximum, &Some(5));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_negative_minimum_and_maximum() {
let schema = json!({
"type": "integer",
"minimum": -100,
"maximum": -1
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(-100));
assert_eq!(maximum, &Some(-1));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_zero_minimum() {
let schema = json!({
"type": "integer",
"minimum": 0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(0));
assert_eq!(maximum, &None);
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_large_values() {
let schema = json!({
"type": "integer",
"minimum": i64::MIN,
"maximum": i64::MAX
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(i64::MIN));
assert_eq!(maximum, &Some(i64::MAX));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_integer_invalid_minimum_type() {
let schema = json!({
"type": "integer",
"minimum": "not_an_integer"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_integer_invalid_maximum_type() {
let schema = json!({
"type": "integer",
"maximum": [1, 2, 3]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_integer_minimum_greater_than_maximum() {
let schema = json!({
"type": "integer",
"minimum": 10,
"maximum": 5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Integer {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(10));
assert_eq!(maximum, &Some(5));
}
_ => panic!("Expected Type::Integer"),
}
}
#[test]
fn test_deserialize_number_all_fields() {
let schema = json!({
"type": "number",
"description": "a number",
"minimum": 1.5,
"maximum": 10.5,
"default": 5.5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("a number"));
assert_eq!(minimum, &Some(1.5));
assert_eq!(maximum, &Some(10.5));
assert_eq!(default, &Some(Value::from(5.5)));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_no_minimum() {
let schema = json!({
"type": "number",
"description": "no min",
"maximum": 100.0,
"default": 50.0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("no min"));
assert_eq!(minimum, &None);
assert_eq!(maximum, &Some(100.0));
assert_eq!(default, &Some(Value::from(50.0)));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_no_maximum() {
let schema = json!({
"type": "number",
"description": "no max",
"minimum": -10.0,
"default": 0.0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description.as_deref(), Some("no max"));
assert_eq!(minimum, &Some(-10.0));
assert_eq!(maximum, &None);
assert_eq!(default, &Some(Value::from(0.0)));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_only_required() {
let schema = json!({
"type": "number"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description, &None);
assert_eq!(minimum, &None);
assert_eq!(maximum, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_minimum_equals_maximum() {
let schema = json!({
"type": "number",
"minimum": 5.5,
"maximum": 5.5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(5.5));
assert_eq!(maximum, &Some(5.5));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_negative_minimum_and_maximum() {
let schema = json!({
"type": "number",
"minimum": -100.25,
"maximum": -1.75
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(-100.25));
assert_eq!(maximum, &Some(-1.75));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_zero_minimum() {
let schema = json!({
"type": "number",
"minimum": 0.0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(0.0));
assert_eq!(maximum, &None);
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_large_values() {
let schema = json!({
"type": "number",
"minimum": f64::MIN,
"maximum": f64::MAX
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(f64::MIN));
assert_eq!(maximum, &Some(f64::MAX));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_number_invalid_minimum_type() {
let schema = json!({
"type": "number",
"minimum": "not_a_number"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_number_invalid_maximum_type() {
let schema = json!({
"type": "number",
"maximum": [1, 2, 3]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_number_minimum_greater_than_maximum() {
let schema = json!({
"type": "number",
"minimum": 10.0,
"maximum": 5.0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Number {
minimum, maximum, ..
} => {
assert_eq!(minimum, &Some(10.0));
assert_eq!(maximum, &Some(5.0));
}
_ => panic!("Expected Type::Number"),
}
}
#[test]
fn test_deserialize_boolean_all_fields() {
let schema = json!({
"type": "boolean",
"description": "a boolean",
"default": true
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Boolean {
description,
default,
} => {
assert_eq!(description.as_deref(), Some("a boolean"));
assert_eq!(default, &Some(Value::from(true)));
}
_ => panic!("Expected Type::Boolean"),
}
}
#[test]
fn test_deserialize_boolean_no_description() {
let schema = json!({
"type": "boolean",
"default": false
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Boolean {
description,
default,
} => {
assert_eq!(description, &None);
assert_eq!(default, &Some(Value::from(false)));
}
_ => panic!("Expected Type::Boolean"),
}
}
#[test]
fn test_deserialize_boolean_no_default() {
let schema = json!({
"type": "boolean",
"description": "no default"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Boolean {
description,
default,
} => {
assert_eq!(description.as_deref(), Some("no default"));
assert_eq!(default, &None);
}
_ => panic!("Expected Type::Boolean"),
}
}
#[test]
fn test_deserialize_boolean_only_required() {
let schema = json!({
"type": "boolean"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Boolean {
description,
default,
} => {
assert_eq!(description, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected Type::Boolean"),
}
}
#[test]
fn test_deserialize_null_all_fields() {
let schema = json!({
"type": "null",
"description": "a null"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Null { description } => {
assert_eq!(description.as_deref(), Some("a null"));
}
_ => panic!("Expected Type::Null"),
}
}
#[test]
fn test_deserialize_null_no_description() {
let schema = json!({
"type": "null"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Null { description } => {
assert_eq!(description, &None);
}
_ => panic!("Expected Type::Null"),
}
}
#[test]
fn test_deserialize_string_all_fields() {
let schema = json!({
"type": "string",
"description": "a string",
"minLength": 2,
"maxLength": 10,
"pattern": "^abc",
"default": "abc"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String {
description,
min_length,
max_length,
pattern,
default,
} => {
assert_eq!(description.as_deref(), Some("a string"));
assert_eq!(min_length, &Some(2));
assert_eq!(max_length, &Some(10));
assert_eq!(pattern.as_deref(), Some("^abc"));
assert_eq!(default, &Some(Value::from("abc")));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_no_min_max_pattern() {
let schema = json!({
"type": "string",
"description": "no min/max/pattern",
"default": "foo"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String {
description,
min_length,
max_length,
pattern,
default,
} => {
assert_eq!(description.as_deref(), Some("no min/max/pattern"));
assert_eq!(min_length, &None);
assert_eq!(max_length, &None);
assert_eq!(pattern, &None);
assert_eq!(default, &Some(Value::from("foo")));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_only_required() {
let schema = json!({
"type": "string"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String {
description,
min_length,
max_length,
pattern,
default,
} => {
assert_eq!(description, &None);
assert_eq!(min_length, &None);
assert_eq!(max_length, &None);
assert_eq!(pattern, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_min_equals_max() {
let schema = json!({
"type": "string",
"minLength": 5,
"maxLength": 5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String {
min_length,
max_length,
..
} => {
assert_eq!(min_length, &Some(5));
assert_eq!(max_length, &Some(5));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_zero_min_length() {
let schema = json!({
"type": "string",
"minLength": 0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String { min_length, .. } => {
assert_eq!(min_length, &Some(0));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_invalid_min_length_type() {
let schema = json!({
"type": "string",
"minLength": "not_a_number"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_string_invalid_max_length_type() {
let schema = json!({
"type": "string",
"maxLength": [1, 2, 3]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_string_empty_pattern() {
let schema = json!({
"type": "string",
"pattern": ""
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String { pattern, .. } => {
assert_eq!(pattern.as_deref(), Some(""));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_unicode_pattern() {
let schema = json!({
"type": "string",
"pattern": "^[\\u4e00-\\u9fa5]+$"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String { pattern, .. } => {
assert_eq!(pattern.as_deref(), Some("^[\\u4e00-\\u9fa5]+$"));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_large_min_max_length() {
let schema = json!({
"type": "string",
"minLength": usize::MAX,
"maxLength": usize::MAX
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::String {
min_length,
max_length,
..
} => {
assert_eq!(min_length, &Some(usize::MAX));
assert_eq!(max_length, &Some(usize::MAX));
}
_ => panic!("Expected Type::String"),
}
}
#[test]
fn test_deserialize_string_invalid_pattern_type() {
let schema = json!({
"type": "string",
"pattern": 123
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_array_only_required() {
let schema = json!({
"type": "array",
"items": { "type": "integer" }
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
description,
items,
min_items,
max_items,
default,
} => {
assert_eq!(description, &None);
assert_eq!(min_items, &None);
assert_eq!(max_items, &None);
assert_eq!(default, &None);
match items.as_type() {
Type::Integer {
description,
minimum,
maximum,
default,
} => {
assert_eq!(description, &None);
assert_eq!(minimum, &None);
assert_eq!(maximum, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected items to be Type::Integer"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_equals_max() {
let schema = json!({
"type": "array",
"items": { "type": "boolean" },
"minItems": 3,
"maxItems": 3
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(3));
assert_eq!(max_items, &Some(3));
match items.as_type() {
Type::Boolean {
description,
default,
} => {
assert_eq!(description, &None);
assert_eq!(default, &None);
}
_ => panic!("Expected items to be Type::Boolean"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_zero_min_items() {
let schema = json!({
"type": "array",
"items": { "type": "null" },
"minItems": 0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items, items, ..
} => {
assert_eq!(min_items, &Some(0));
match items.as_type() {
Type::Null { description } => {
assert_eq!(description, &None);
}
_ => panic!("Expected items to be Type::Null"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_greater_than_max() {
let schema = json!({
"type": "array",
"items": { "type": "string" },
"minItems": 10,
"maxItems": 5
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(10));
assert_eq!(max_items, &Some(5));
match items.as_type() {
Type::String { .. } => {}
_ => panic!("Expected items to be Type::String"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_large_min_max() {
let schema = json!({
"type": "array",
"items": { "type": "number" },
"minItems": usize::MAX,
"maxItems": usize::MAX
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(usize::MAX));
assert_eq!(max_items, &Some(usize::MAX));
match items.as_type() {
Type::Number { .. } => {}
_ => panic!("Expected items to be Type::Number"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_invalid_min_items_type() {
let schema = json!({
"type": "array",
"items": { "type": "string" },
"minItems": "not_a_number"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_array_invalid_max_items_type() {
let schema = json!({
"type": "array",
"items": { "type": "string" },
"maxItems": [1, 2, 3]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_array_invalid_items_type() {
let schema = json!({
"type": "array",
"items": 123
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_array_items_with_fields() {
let schema = json!({
"type": "array",
"items": {
"type": "string",
"description": "inner string",
"minLength": 1,
"maxLength": 8,
"pattern": "foo",
"default": "bar"
},
"minItems": 1,
"maxItems": 2,
"description": "outer array",
"default": ["bar"]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
description,
items,
min_items,
max_items,
default,
} => {
assert_eq!(description.as_deref(), Some("outer array"));
assert_eq!(min_items, &Some(1));
assert_eq!(max_items, &Some(2));
assert_eq!(
default,
&Some(Value::Array(Rc::new(vec![Value::from("bar")])))
);
match items.as_type() {
Type::String {
description,
min_length,
max_length,
pattern,
default,
} => {
assert_eq!(description.as_deref(), Some("inner string"));
assert_eq!(min_length, &Some(1));
assert_eq!(max_length, &Some(8));
assert_eq!(pattern.as_deref(), Some("foo"));
assert_eq!(default, &Some(Value::from("bar")));
}
_ => panic!("Expected items to be Type::String"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_items_none_max_items_some() {
let schema = json!({
"type": "array",
"items": { "type": "string" },
"maxItems": 7
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &None);
assert_eq!(max_items, &Some(7));
match items.as_type() {
Type::String { .. } => {}
_ => panic!("Expected items to be Type::String"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_items_some_max_items_none() {
let schema = json!({
"type": "array",
"items": { "type": "boolean" },
"minItems": 2
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(2));
assert_eq!(max_items, &None);
match items.as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected items to be Type::Boolean"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_items_zero_max_items_zero() {
let schema = json!({
"type": "array",
"items": { "type": "null" },
"minItems": 0,
"maxItems": 0
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(0));
assert_eq!(max_items, &Some(0));
match items.as_type() {
Type::Null { .. } => {}
_ => panic!("Expected items to be Type::Null"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_min_items_greater_than_max_items() {
let schema = json!({
"type": "array",
"items": { "type": "number" },
"minItems": 5,
"maxItems": 2
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(5));
assert_eq!(max_items, &Some(2));
match items.as_type() {
Type::Number { .. } => {}
_ => panic!("Expected items to be Type::Number"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_array_items_with_nested_array() {
let schema = json!({
"type": "array",
"items": {
"type": "array",
"items": { "type": "integer" },
"minItems": 1,
"maxItems": 2
},
"minItems": 2,
"maxItems": 3
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Array {
min_items,
max_items,
items,
..
} => {
assert_eq!(min_items, &Some(2));
assert_eq!(max_items, &Some(3));
match items.as_type() {
Type::Array {
min_items: inner_min,
max_items: inner_max,
items: inner_items,
..
} => {
assert_eq!(inner_min, &Some(1));
assert_eq!(inner_max, &Some(2));
match inner_items.as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected nested items to be Type::Integer"),
}
}
_ => panic!("Expected items to be Type::Array"),
}
}
_ => panic!("Expected Type::Array"),
}
}
#[test]
fn test_deserialize_object_all_fields() {
let schema = json!({
"type": "object",
"description": "an object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "integer" }
},
"required": ["foo"],
"additionalProperties": { "type": "boolean" },
"name": "MyObject",
"default": { "foo": "abc", "bar": 42 }
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
description,
properties,
required,
additional_properties,
name,
default,
discriminated_subobject,
} => {
assert_eq!(description.as_deref(), Some("an object"));
assert_eq!(name.as_deref(), Some("MyObject"));
assert_eq!(
default,
&Some(Value::Object(Rc::new(
[
("foo".into(), Value::from("abc")),
("bar".into(), Value::from(42))
]
.iter()
.cloned()
.collect()
)))
);
assert_eq!(properties.len(), 2);
match properties.get("foo").unwrap().as_type() {
Type::String { .. } => {}
_ => panic!("Expected foo to be Type::String"),
}
match properties.get("bar").unwrap().as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected bar to be Type::Integer"),
}
let req = required.as_ref().expect("required should be present");
assert_eq!(req.len(), 1);
assert_eq!(req[0].as_ref(), "foo");
match additional_properties.as_ref().unwrap().as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected additionalProperties to be Type::Boolean"),
}
assert!(discriminated_subobject.is_none());
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_only_required() {
let schema = json!({
"type": "object",
"properties": {}
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
description,
properties,
required,
additional_properties,
name,
default,
discriminated_subobject,
} => {
assert_eq!(description, &None);
assert_eq!(properties.len(), 0);
assert!(required.is_none());
assert!(matches!(
additional_properties.as_ref().unwrap().as_type(),
Type::Any { .. }
));
assert!(name.is_none());
assert!(default.is_none());
assert!(discriminated_subobject.is_none());
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_with_required_and_additional_properties() {
let schema = json!({
"type": "object",
"properties": {
"x": { "type": "number" }
},
"required": ["x"],
"additionalProperties": { "type": "string" }
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
properties,
required,
additional_properties,
..
} => {
assert_eq!(properties.len(), 1);
match properties.get("x").unwrap().as_type() {
Type::Number { .. } => {}
_ => panic!("Expected x to be Type::Number"),
}
let req = required.as_ref().expect("required should be present");
assert_eq!(req.len(), 1);
assert_eq!(req[0].as_ref(), "x");
match additional_properties.as_ref().unwrap().as_type() {
Type::String { .. } => {}
_ => panic!("Expected additionalProperties to be Type::String"),
}
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_with_discriminated_subobject() {
let schema = json!({
"type": "object",
"properties": {},
"allOf": [
{
"if": { "properties": { "kind": { "const": "foo" } } },
"then": {
"properties": { "foo": { "type": "string" } },
"required": ["foo"]
}
},
{
"if": { "properties": { "kind": { "const": "bar" } } },
"then": {
"properties": { "bar": { "type": "integer" } },
"required": ["bar"]
}
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
discriminated_subobject,
..
} => {
let dso = discriminated_subobject
.as_ref()
.expect("should have discriminated_subobject");
assert_eq!(dso.discriminator.as_ref(), "kind");
assert_eq!(dso.variants.len(), 2);
let foo_variant = dso.variants.get("foo").expect("foo variant");
assert!(foo_variant.properties.contains_key("foo"));
let bar_variant = dso.variants.get("bar").expect("bar variant");
assert!(bar_variant.properties.contains_key("bar"));
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_invalid_properties_type() {
let schema = json!({
"type": "object",
"properties": 123
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_object_invalid_required_type() {
let schema = json!({
"type": "object",
"properties": {},
"required": "not_an_array"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_object_invalid_additional_properties_type() {
let schema = json!({
"type": "object",
"properties": {},
"additionalProperties": 123
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_object_empty_properties_and_required() {
let schema = json!({
"type": "object",
"properties": {},
"required": []
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
properties,
required,
..
} => {
assert_eq!(properties.len(), 0);
let req = required.as_ref().expect("required should be present");
assert!(req.is_empty());
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_required_not_in_properties() {
let schema = json!({
"type": "object",
"properties": { "x": { "type": "string" } },
"required": ["y"]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
properties,
required,
..
} => {
assert_eq!(properties.len(), 1);
let req = required.as_ref().expect("required should be present");
assert_eq!(req.len(), 1);
assert_eq!(req[0].as_ref(), "y");
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_additional_properties_none() {
let schema = json!({
"type": "object",
"properties": { "foo": { "type": "string" } }
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
additional_properties,
..
} => {
match additional_properties.as_ref().unwrap().as_type() {
Type::Any { .. } => {}
_ => panic!("Expected additionalProperties to default to Type::Any"),
}
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_additional_properties_false() {
let schema = json!({
"type": "object",
"properties": { "foo": { "type": "string" } },
"additionalProperties": false
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
additional_properties,
..
} => {
assert!(
additional_properties.is_none(),
"Expected additionalProperties to be None when set to false"
);
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_additional_properties_true() {
let schema = json!({
"type": "object",
"properties": { "foo": { "type": "string" } },
"additionalProperties": true
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
additional_properties,
..
} => {
match additional_properties.as_ref().unwrap().as_type() {
Type::Any { .. } => {}
_ => panic!("Expected additionalProperties to be Type::Any when set to true"),
}
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_name_field_only() {
let schema = json!({
"type": "object",
"properties": {},
"name": "OnlyName"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object { name, .. } => {
assert_eq!(name.as_deref(), Some("OnlyName"));
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_default_empty_object() {
let schema = json!({
"type": "object",
"properties": {},
"default": {}
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object { default, .. } => {
assert_eq!(default, &Some(Value::Object(Rc::new(BTreeMap::new()))));
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_with_empty_discriminated_subobject() {
let schema = json!({
"type": "object",
"properties": {},
"allOf": []
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_object_nested_2_levels() {
let schema = json!({
"type": "object",
"properties": {
"level1": {
"type": "object",
"properties": {
"level2": { "type": "string" }
}
}
}
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object { properties, .. } => {
let level1 = properties.get("level1").expect("level1 property");
match level1.as_type() {
Type::Object {
properties: props2, ..
} => {
let level2 = props2.get("level2").expect("level2 property");
match level2.as_type() {
Type::String { .. } => {}
_ => panic!("Expected level2 to be Type::String"),
}
}
_ => panic!("Expected level1 to be Type::Object"),
}
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_object_nested_3_levels() {
let schema = json!({
"type": "object",
"properties": {
"a": {
"type": "object",
"properties": {
"b": {
"type": "object",
"properties": {
"c": { "type": "integer" }
}
}
}
}
}
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object { properties, .. } => {
let a = properties.get("a").expect("a property");
match a.as_type() {
Type::Object {
properties: props_b,
..
} => {
let b = props_b.get("b").expect("b property");
match b.as_type() {
Type::Object {
properties: props_c,
..
} => {
let c = props_c.get("c").expect("c property");
match c.as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected c to be Type::Integer"),
}
}
_ => panic!("Expected b to be Type::Object"),
}
}
_ => panic!("Expected a to be Type::Object"),
}
}
_ => panic!("Expected Type::Object"),
}
}
#[test]
fn test_deserialize_enum_all_fields() {
let schema = json!({
"enum": ["foo", "bar", 42, true, null],
"description": "an enum"
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum {
description,
values,
} => {
assert_eq!(description.as_deref(), Some("an enum"));
assert_eq!(values.len(), 5);
assert_eq!(values[0], Value::from("foo"));
assert_eq!(values[1], Value::from("bar"));
assert_eq!(values[2], Value::from(42));
assert_eq!(values[3], Value::from(true));
assert_eq!(values[4], Value::Null);
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_only_required() {
let schema = json!({
"enum": ["a", "b"]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum {
description,
values,
} => {
assert_eq!(description, &None);
assert_eq!(values.len(), 2);
assert_eq!(values[0], Value::from("a"));
assert_eq!(values[1], Value::from("b"));
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_empty_values() {
let schema = json!({
"enum": [],
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert!(values.is_empty());
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_single_value() {
let schema = json!({
"enum": [123]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert_eq!(values.len(), 1);
assert_eq!(values[0], Value::from(123));
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_mixed_types() {
let schema = json!({
"enum": ["x", 1, false, null, {"foo": "bar"}, [1,2,3]]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert_eq!(values.len(), 6);
assert_eq!(values[0], Value::from("x"));
assert_eq!(values[1], Value::from(1));
assert_eq!(values[2], Value::from(false));
assert_eq!(values[3], Value::Null);
match &values[4] {
Value::Object(obj) => {
assert_eq!(obj.get(&Value::from("foo")), Some(&Value::from("bar")))
}
_ => panic!("Expected object in enum values"),
}
match &values[5] {
Value::Array(arr) => {
assert_eq!(arr.len(), 3);
assert_eq!(arr[0], Value::from(1));
assert_eq!(arr[1], Value::from(2));
assert_eq!(arr[2], Value::from(3));
}
_ => panic!("Expected array in enum values"),
}
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_invalid_values_type() {
let schema = json!({
"enum": "not_an_array"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_enum_with_duplicate_values() {
let schema = json!({
"enum": ["dup", "dup", 1, 1, null, null]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert_eq!(values.len(), 6);
assert_eq!(values[0], Value::from("dup"));
assert_eq!(values[1], Value::from("dup"));
assert_eq!(values[2], Value::from(1));
assert_eq!(values[3], Value::from(1));
assert_eq!(values[4], Value::Null);
assert_eq!(values[5], Value::Null);
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_all_values_null() {
let schema = json!({
"enum": [null, null, null]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert_eq!(values.len(), 3);
assert!(values.iter().all(|v| *v == Value::Null));
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_large_number_of_values() {
let values: Vec<_> = (0..1000).map(Value::from).collect();
let schema = json!({
"enum": values
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => {
assert_eq!(values.len(), 1000);
assert_eq!(values[0], Value::from(0));
assert_eq!(values[999], Value::from(999));
}
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_values_with_object_non_string_keys() {
let schema = json!({
"enum": [
{ "1": "one", "true": "bool" }
]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => match &values[0] {
Value::Object(obj) => {
assert_eq!(obj[&Value::from("1")], Value::from("one"));
assert_eq!(obj[&Value::from("true")], Value::from("bool"));
}
_ => panic!("Expected object in enum values"),
},
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_enum_values_with_deeply_nested_structures() {
let schema = json!({
"enum": [
{
"a": [
{ "b": [1, 2, { "c": null }] }
]
}
]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Enum { values, .. } => match &values[0] {
Value::Object(obj) => {
let a = &obj[&Value::from("a")];
match a {
Value::Array(arr) => match &arr[0] {
Value::Object(inner) => {
let b = &inner[&Value::from("b")];
match b {
Value::Array(barr) => {
assert_eq!(barr[0], Value::from(1));
assert_eq!(barr[1], Value::from(2));
match &barr[2] {
Value::Object(cobj) => {
assert_eq!(cobj[&Value::from("c")], Value::Null);
}
_ => panic!("Expected object for 'c'"),
}
}
_ => panic!("Expected array for 'b'"),
}
}
_ => panic!("Expected object in 'a' array"),
},
_ => panic!("Expected array for 'a'"),
}
}
_ => panic!("Expected object in enum values"),
},
_ => panic!("Expected Type::Enum"),
}
}
#[test]
fn test_deserialize_const_all_fields() {
let schema = json!({
"const": 42,
"description": "a constant",
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { description, value } => {
assert_eq!(description.as_deref(), Some("a constant"));
assert_eq!(value, &Value::from(42));
}
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_only_required() {
let schema = json!({
"const": "foo"
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { description, value } => {
assert_eq!(description, &None);
assert_eq!(value, &Value::from("foo"));
}
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_value_null() {
let schema = json!({
"const": null
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { value, .. } => {
assert_eq!(value, &Value::Null);
}
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_value_object() {
let schema = json!({
"const": { "foo": "bar", "baz": 1 }
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { value, .. } => match value {
Value::Object(ref obj) => {
assert_eq!(obj[&Value::from("foo")], Value::from("bar"));
assert_eq!(obj[&Value::from("baz")], Value::from(1));
}
_ => panic!("Expected object for const value"),
},
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_value_array() {
let schema = json!({
"const": [1, 2, 3]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { value, .. } => match value {
Value::Array(ref arr) => {
assert_eq!(arr.len(), 3);
assert_eq!(arr[0], Value::from(1));
assert_eq!(arr[1], Value::from(2));
assert_eq!(arr[2], Value::from(3));
}
_ => panic!("Expected array for const value"),
},
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_value_boolean() {
let schema = json!({
"const": true
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { value, .. } => {
assert_eq!(value, &Value::from(true));
}
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_value_deeply_nested() {
let schema = json!({
"const": {
"a": [1, { "b": [null, false] }]
}
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Const { value, .. } => match value {
Value::Object(ref obj) => {
let a = &obj[&Value::from("a")];
match a {
Value::Array(arr) => {
assert_eq!(arr[0], Value::from(1));
match &arr[1] {
Value::Object(inner) => {
let b = &inner[&Value::from("b")];
match b {
Value::Array(barr) => {
assert_eq!(barr[0], Value::Null);
assert_eq!(barr[1], Value::from(false));
}
_ => panic!("Expected array for 'b'"),
}
}
_ => panic!("Expected object in 'a' array"),
}
}
_ => panic!("Expected array for 'a'"),
}
}
_ => panic!("Expected object for const value"),
},
_ => panic!("Expected Type::Const"),
}
}
#[test]
fn test_deserialize_const_invalid_missing_value() {
let schema = json!({
"type": "const"
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_basic() {
let schema = json!({
"anyOf": [
{ "type": "string" },
{ "type": "integer" }
]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 2);
match variants[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected first variant to be Type::String"),
}
match variants[1].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected second variant to be Type::Integer"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_single_variant() {
let schema = json!({
"anyOf": [
{ "type": "string" }
]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 1);
match variants[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected variant to be Type::String"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_empty() {
let schema = json!({
"anyOf": []
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert!(variants.is_empty());
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_mixed_types() {
let schema = json!({
"anyOf": [
{ "type": "string" },
{ "type": "integer" },
{ "type": "array", "items": { "type": "boolean" } },
{ "type": "object", "properties": { "foo": { "type": "null" } } }
]
});
let s: Schema = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 4);
match variants[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected variant 0 to be Type::String"),
}
match variants[1].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected variant 1 to be Type::Integer"),
}
match variants[2].as_type() {
Type::Array { items, .. } => match items.as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected array items to be Type::Boolean"),
},
_ => panic!("Expected variant 2 to be Type::Array"),
}
match variants[3].as_type() {
Type::Object { properties, .. } => {
assert!(properties.contains_key("foo"));
}
_ => panic!("Expected variant 3 to be Type::Object"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_invalid_variants_type() {
let schema = json!({
"anyOf": "not_an_array"
});
let result: Result<Schema, _> = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_missing_anyof() {
let schema = json!({});
let result: Result<Schema, _> = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_with_invalid_variant() {
let schema = json!({
"anyOf": [
{ "type": "string" },
123
]
});
let result: Result<Schema, _> = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_deeply_nested() {
let schema = json!({
"anyOf": [
{
"anyOf": [
{ "type": "string" },
{ "type": "integer" }
]
},
{ "type": "boolean" }
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 2);
match variants[0].as_type() {
Type::AnyOf(inner) => {
assert_eq!(inner.len(), 2);
match inner[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected inner variant 0 to be Type::String"),
}
match inner[1].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected inner variant 1 to be Type::Integer"),
}
}
_ => panic!("Expected first variant to be Type::AnyOf"),
}
match variants[1].as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected second variant to be Type::Boolean"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_all_null() {
let schema = json!({
"anyOf": [null, null, null]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_with_duplicates() {
let schema = json!({
"anyOf": [
{ "type": "string" },
{ "type": "string" },
{ "type": "integer" },
{ "type": "integer" }
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 4);
match variants[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected variant 0 to be Type::String"),
}
match variants[1].as_type() {
Type::String { .. } => {}
_ => panic!("Expected variant 1 to be Type::String"),
}
match variants[2].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected variant 2 to be Type::Integer"),
}
match variants[3].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected variant 3 to be Type::Integer"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_large_number_of_variants() {
let variants: Vec<_> = (0..100)
.map(|i| json!({ "type": "integer", "default": i }))
.collect();
let schema = json!({
"anyOf": variants
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 100);
for (i, v) in variants.iter().enumerate() {
match v.as_type() {
Type::Integer { default, .. } => {
assert_eq!(default, &Some(Value::from(i as i64)));
}
_ => panic!("Expected all variants to be Type::Integer"),
}
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_deeply_nested_multiple_levels() {
let schema = json!({
"anyOf": [
{
"anyOf": [
{
"anyOf": [
{ "type": "string" }
]
}
]
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(outer) => {
assert_eq!(outer.len(), 1);
match outer[0].as_type() {
Type::AnyOf(middle) => {
assert_eq!(middle.len(), 1);
match middle[0].as_type() {
Type::AnyOf(inner) => {
assert_eq!(inner.len(), 1);
match inner[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected innermost to be Type::String"),
}
}
_ => panic!("Expected middle to be Type::AnyOf"),
}
}
_ => panic!("Expected outer to be Type::AnyOf"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_empty_object_variant() {
let schema = json!({
"anyOf": [
{}
]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_with_invalid_schema_in_list() {
let schema = json!({
"anyOf": [
{ "type": "string" },
{ "foo": "bar" }
]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
}
#[test]
fn test_deserialize_anyof_all_same_variant() {
let schema = json!({
"anyOf": [
{ "type": "boolean" },
{ "type": "boolean" },
{ "type": "boolean" }
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 3);
for v in variants.iter() {
match v.as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected all variants to be Type::Boolean"),
}
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_nested_types() {
let schema = json!({
"anyOf": [
{ "type": "string", "minLength": 2 },
{ "type": "integer", "minimum": 0 },
{
"type": "array",
"items": { "type": "boolean" },
"minItems": 1
},
{
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "number" }
},
"required": ["foo"]
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 4);
match &variants[0].as_type() {
Type::String { min_length, .. } => assert_eq!(min_length, &Some(2)),
_ => panic!("Expected first variant to be Type::String"),
}
match &variants[1].as_type() {
Type::Integer { minimum, .. } => assert_eq!(minimum, &Some(0)),
_ => panic!("Expected second variant to be Type::Integer"),
}
match &variants[2].as_type() {
Type::Array {
items, min_items, ..
} => {
assert_eq!(min_items, &Some(1));
match items.as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected array items to be Type::Boolean"),
}
}
_ => panic!("Expected third variant to be Type::Array"),
}
match &variants[3].as_type() {
Type::Object {
properties,
required,
..
} => {
assert!(properties.contains_key("foo"));
assert!(properties.contains_key("bar"));
let req = required.as_ref().expect("required should be present");
assert_eq!(req[0].as_ref(), "foo");
}
_ => panic!("Expected fourth variant to be Type::Object"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_deeply_nested_anyof() {
let schema = json!({
"anyOf": [
{
"anyOf": [
{ "type": "string" },
{ "type": "null" }
]
},
{ "type": "integer" }
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 2);
match &variants[0].as_type() {
Type::AnyOf(inner_variants) => {
assert_eq!(inner_variants.len(), 2);
match inner_variants[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected inner variant 0 to be Type::String"),
}
match inner_variants[1].as_type() {
Type::Null { .. } => {}
_ => panic!("Expected inner variant 1 to be Type::Null"),
}
}
_ => panic!("Expected first variant to be Type::AnyOf"),
}
match &variants[1].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected second variant to be Type::Integer"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_enum_and_const() {
let schema = json!({
"anyOf": [
{
"enum": ["a", "b", "c"]
},
{
"const": 42
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 2);
match &variants[0].as_type() {
Type::Enum { values, .. } => {
assert_eq!(
values.as_ref(),
&vec![Value::from("a"), Value::from("b"), Value::from("c")]
);
}
_ => panic!("Expected first variant to be Type::Enum"),
}
match &variants[1].as_type() {
Type::Const { value, .. } => {
assert_eq!(value, &Value::from(42));
}
_ => panic!("Expected second variant to be Type::Const"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_complex_nesting() {
let schema = json!({
"anyOf": [
{
"type": "object",
"properties": {
"x": {
"anyOf": [
{ "type": "string" },
{ "type": "integer" }
]
}
}
},
{
"type": "array",
"items": {
"anyOf": [
{ "type": "boolean" },
{ "type": "null" }
]
}
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 2);
match &variants[0].as_type() {
Type::Object { properties, .. } => {
let x = properties.get("x").expect("x property");
match x.as_type() {
Type::AnyOf(inner) => {
assert_eq!(inner.len(), 2);
match inner[0].as_type() {
Type::String { .. } => {}
_ => panic!("Expected x.anyOf[0] to be Type::String"),
}
match inner[1].as_type() {
Type::Integer { .. } => {}
_ => panic!("Expected x.anyOf[1] to be Type::Integer"),
}
}
_ => panic!("Expected x to be Type::AnyOf"),
}
}
_ => panic!("Expected first variant to be Type::Object"),
}
match &variants[1].as_type() {
Type::Array { items, .. } => match items.as_type() {
Type::AnyOf(inner) => {
assert_eq!(inner.len(), 2);
match inner[0].as_type() {
Type::Boolean { .. } => {}
_ => panic!("Expected items.anyOf[0] to be Type::Boolean"),
}
match inner[1].as_type() {
Type::Null { .. } => {}
_ => panic!("Expected items.anyOf[1] to be Type::Null"),
}
}
_ => panic!("Expected items to be Type::AnyOf"),
},
_ => panic!("Expected second variant to be Type::Array"),
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_duplicate_and_null_variants() {
let schema = json!({
"anyOf": [
{ "type": "null" },
{ "type": "null" },
{ "type": "string" },
{ "type": "string" }
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 4);
assert!(matches!(variants[0].as_type(), Type::Null { .. }));
assert!(matches!(variants[1].as_type(), Type::Null { .. }));
assert!(matches!(variants[2].as_type(), Type::String { .. }));
assert!(matches!(variants[3].as_type(), Type::String { .. }));
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_anyof_with_large_number_of_variants() {
let variants: Vec<_> = (0..100)
.map(|i| json!({ "type": "integer", "minimum": i }))
.collect();
let schema = json!({ "anyOf": variants });
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::AnyOf(variants) => {
assert_eq!(variants.len(), 100);
for (i, v) in variants.iter().enumerate() {
match v.as_type() {
Type::Integer { minimum, .. } => assert_eq!(minimum, &Some(i as i64)),
_ => panic!("Expected variant {} to be Type::Integer", i),
}
}
}
_ => panic!("Expected Type::AnyOf"),
}
}
#[test]
fn test_deserialize_object_with_mixed_discriminators_error() {
let schema = json!({
"type": "object",
"peekoo": 1,
"properties": {
"name": { "type": "string" }
},
"allOf": [
{
"if": {
"properties": {
"type": { "const": "user" }
}
},
"then": {
"properties": {
"email": { "type": "string" }
},
"required": ["email"]
}
},
{
"if": {
"properties": {
"kind": { "const": "admin" } }
},
"then": {
"properties": {
"permissions": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["permissions"]
}
}
]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
let error_msg = format!("{}", result.unwrap_err());
assert!(error_msg.contains("single discriminator"));
}
#[test]
fn test_deserialize_object_with_multiple_discriminator_properties_error() {
let schema = json!({
"type": "object",
"properties": {
"name": { "type": "string" }
},
"allOf": [
{
"if": {
"properties": {
"type": { "const": "user" },
"category": { "const": "external" } }
},
"then": {
"properties": {
"email": { "type": "string" }
}
}
}
]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
let error_msg = format!("{}", result.unwrap_err());
assert!(error_msg.contains("exactly one property"));
}
#[test]
fn test_deserialize_object_with_no_discriminator_properties_error() {
let schema = json!({
"type": "object",
"properties": {
"name": { "type": "string" }
},
"allOf": [
{
"if": {
"properties": {} },
"then": {
"properties": {
"email": { "type": "string" }
}
}
}
]
});
let result = Schema::from_serde_json_value(schema);
assert!(result.is_err());
let error_msg = format!("{}", result.unwrap_err());
assert!(error_msg.contains("exactly one property"));
}
#[test]
fn test_deserialize_object_with_consistent_discriminator_success() {
let schema = json!({
"type": "object",
"properties": {
"name": { "type": "string" },
"entityType": { "type": "string" }
},
"required": ["name", "entityType"],
"allOf": [
{
"if": {
"properties": {
"entityType": { "const": "user" }
}
},
"then": {
"properties": {
"email": { "type": "string" },
"lastLogin": { "type": "string" }
},
"required": ["email"]
}
},
{
"if": {
"properties": {
"entityType": { "const": "group" }
}
},
"then": {
"properties": {
"members": {
"type": "array",
"items": { "type": "string" }
},
"permissions": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["members"]
}
},
{
"if": {
"properties": {
"entityType": { "const": "service" }
}
},
"then": {
"properties": {
"endpoint": { "type": "string" },
"healthCheck": { "type": "string" },
"version": { "type": "string" }
},
"required": ["endpoint", "version"]
}
}
]
});
let s = Schema::from_serde_json_value(schema).unwrap();
match s.as_type() {
Type::Object {
discriminated_subobject,
properties,
required,
..
} => {
assert!(properties.contains_key("name"));
assert!(properties.contains_key("entityType"));
let req = required.as_ref().expect("required should be present");
assert!(req.contains(&"name".into()));
assert!(req.contains(&"entityType".into()));
let dso = discriminated_subobject
.as_ref()
.expect("should have discriminated_subobject");
assert_eq!(dso.discriminator.as_ref(), "entityType");
assert_eq!(dso.variants.len(), 3);
let user_variant = dso.variants.get("user").expect("user variant");
assert!(user_variant.properties.contains_key("email"));
assert!(user_variant.properties.contains_key("lastLogin"));
let user_req = user_variant.required.as_ref().expect("user required");
assert!(user_req.contains(&"email".into()));
let group_variant = dso.variants.get("group").expect("group variant");
assert!(group_variant.properties.contains_key("members"));
assert!(group_variant.properties.contains_key("permissions"));
let group_req = group_variant.required.as_ref().expect("group required");
assert!(group_req.contains(&"members".into()));
let service_variant = dso.variants.get("service").expect("service variant");
assert!(service_variant.properties.contains_key("endpoint"));
assert!(service_variant.properties.contains_key("healthCheck"));
assert!(service_variant.properties.contains_key("version"));
let service_req = service_variant.required.as_ref().expect("service required");
assert!(service_req.contains(&"endpoint".into()));
assert!(service_req.contains(&"version".into()));
}
_ => panic!("Expected Type::Object"),
}
}