//! Typed dictionary results retain their value contracts in both directions. use sausage_interface::compat::check; use serde_json::{Value, json}; fn document(schema: Value) -> Value { json!({"methods":[{"name":"values","params":[],"result":{"schema":schema}}]}) } fn map(value: Value) -> Value { json!({"type":"object","additionalProperties":value}) } #[test] fn dictionary_values_are_covariant() { let strings = document(map(json!({"type":"string"}))); let numbers = document(map(json!({"type":"integer"}))); let short = document(map(json!({"type":"string","enum":["ok"]}))); assert!(check(&strings, &strings).is_empty()); assert!(check(&strings, &short).is_empty()); assert!(!check(&short, &strings).is_empty()); let errors = check(&strings, &numbers); assert_eq!(errors.len(), 1); assert_eq!(errors[0].counterexample, Some(json!({"extra":0}))); } #[test] fn dictionaries_and_named_fields_check_each_other() { let strings = document(map(json!({"type":"string"}))); let named_string = document(json!({"type":"object","properties":{"name":{"type":"string"}}})); let named_number = document(json!({"type":"object","properties":{"name":{"type":"integer"}}})); assert!(check(&strings, &named_string).is_empty()); assert!(check(&named_string, &strings).is_empty()); assert!(!check(&strings, &named_number).is_empty()); assert!(!check(&named_number, &strings).is_empty()); let closed = document(json!({"type":"object","additionalProperties":false})); assert!(!check(&closed, &strings).is_empty()); assert!(check(&strings, &closed).is_empty()); let required = document( json!({"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}), ); assert!(!check(&required, &strings).is_empty()); } #[test] fn dictionary_references_are_checked_not_ignored() { let mut expected = document(map(json!({"$ref":"#/components/schemas/Value"}))); expected["components"]["schemas"]["Value"] = json!({"type":"string"}); assert!(check(&expected, &expected).is_empty()); let mut actual = expected.clone(); actual["components"]["schemas"]["Value"] = json!({"type":"boolean"}); assert!(!check(&expected, &actual).is_empty()); actual["components"]["schemas"]["Value"] = json!({"pattern":"x"}); assert!( check(&expected, &actual)[0] .message .contains("unsupported schema construct pattern") ); }