#![cfg(feature = "serde_json")]
use cddl_cat::json::validate_json_str;
use serde::{Deserialize, Serialize};
#[test]
fn validate_json_null() {
let cddl_input = r#"thing = nil"#;
validate_json_str("thing", cddl_input, "null").unwrap();
validate_json_str("thing", cddl_input, "0").unwrap_err();
validate_json_str("thing", cddl_input, "false").unwrap_err();
}
#[test]
fn validate_json_bool() {
let cddl_input = r#"thing = true"#;
validate_json_str("thing", cddl_input, "true").unwrap();
validate_json_str("thing", cddl_input, "false").unwrap_err();
validate_json_str("thing", cddl_input, "null").unwrap_err();
}
#[test]
fn validate_json_float() {
let cddl_input = r#"thing = 0.0"#;
validate_json_str("thing", cddl_input, "0.0").unwrap();
validate_json_str("thing", cddl_input, "1.0").unwrap_err();
let cddl_input = r#"thing = float"#;
validate_json_str("thing", cddl_input, "1.0").unwrap();
validate_json_str("thing", cddl_input, "1e5").unwrap();
validate_json_str("thing", cddl_input, "1e300").unwrap();
let cddl_input = r#"thing = float16"#;
validate_json_str("thing", cddl_input, "1.0").unwrap();
let cddl_input = r#"thing = float32"#;
validate_json_str("thing", cddl_input, "1.0").unwrap();
validate_json_str("thing", cddl_input, "1e5").unwrap();
let cddl_input = r#"thing = float64"#;
validate_json_str("thing", cddl_input, "1.0").unwrap();
validate_json_str("thing", cddl_input, "1e300").unwrap();
}
#[test]
fn validate_json_choice() {
let cddl_input = r#"thing = 23 / 24"#;
validate_json_str("thing", cddl_input, "23").unwrap();
validate_json_str("thing", cddl_input, "24").unwrap();
let cddl_input = r#"thing = (foo // bar) foo = (int / float) bar = tstr"#;
validate_json_str("thing", cddl_input, "23").unwrap();
validate_json_str("thing", cddl_input, "1.0").unwrap();
validate_json_str("thing", cddl_input, r#""JSON""#).unwrap();
validate_json_str("thing", cddl_input, "true").unwrap_err();
}
#[test]
fn validate_json_integer() {
let cddl_input = r#"thing = 1"#;
validate_json_str("thing", cddl_input, "null").unwrap_err();
validate_json_str("thing", cddl_input, "1.0").unwrap_err();
validate_json_str("thing", cddl_input, "true").unwrap_err();
let cddl_input = r#"thing = int"#;
validate_json_str("thing", cddl_input, "0").unwrap();
validate_json_str("thing", cddl_input, "24").unwrap();
validate_json_str("thing", cddl_input, "-1000").unwrap();
validate_json_str("thing", cddl_input, "1.0").unwrap_err();
let cddl_input = r#"thing = uint"#;
validate_json_str("thing", cddl_input, "0").unwrap();
validate_json_str("thing", cddl_input, "24").unwrap();
validate_json_str("thing", cddl_input, "-1000").unwrap_err();
let cddl_input = r#"thing = nint"#;
validate_json_str("thing", cddl_input, "-1000").unwrap();
validate_json_str("thing", cddl_input, "0").unwrap_err();
validate_json_str("thing", cddl_input, "24").unwrap_err();
}
#[test]
fn validate_json_textstring() {
for cddl_input in [r#"thing = tstr"#, r#"thing = text"#].iter() {
validate_json_str("thing", cddl_input, r#""""#).unwrap();
validate_json_str("thing", cddl_input, r#""JSON""#).unwrap();
validate_json_str("thing", cddl_input, r#""æ°´""#).unwrap();
}
}
#[test]
fn validate_json_array() {
let cddl_input = r#"thing = []"#;
validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "null").unwrap_err();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"thing = [1, 2, 3]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
}
#[derive(Debug, Serialize, Deserialize)]
struct PersonStruct {
name: String,
age: u32,
}
#[derive(Debug, Serialize, Deserialize)]
struct PersonTuple(String, u32);
#[derive(Debug, Serialize, Deserialize)]
struct BackwardsTuple(u32, String);
#[derive(Debug, Serialize, Deserialize)]
struct LongTuple(String, u32, u32);
#[derive(Debug, Serialize, Deserialize)]
struct ShortTuple(String);
#[derive(Debug, Serialize, Deserialize)]
struct KitchenSink(String, u32, f64, bool);
#[test]
fn validate_json_homogenous_array() {
let cddl_input = r#"thing = [* int]"#; validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [+ int]"#; validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
validate_json_str("thing", cddl_input, "[]").unwrap_err();
let cddl_input = r#"thing = [? int]"#; validate_json_str("thing", cddl_input, "[]").unwrap();
let json_str = serde_json::to_string(&[42]).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"thing = [* tstr]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"thing = [* zipcode] zipcode = int"#;
validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
}
#[test]
fn validate_json_array_groups() {
let cddl_input = r#"thing = [int, (int, int)]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [(int, int, int)]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [* (int)]"#;
validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [* (int, int, int)]"#;
validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [* (int, int)]"#;
validate_json_str("thing", cddl_input, "[]").unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"thing = [a: int, b: int, bar] bar = (c: int)"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [a: int, (bar)] bar = (b: int, c: int)"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [a: int, b: bar] bar = (b: int, c: int)"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
}
#[test]
fn validate_json_array_unwrap() {
let cddl_input = r#"header = [a: int, b: int] thing = [~header c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
validate_json_str("thing", cddl_input, "[]").unwrap_err();
let cddl_input = r#"footer = [a: int, b: int] thing = [c: int ~footer]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"middle = [int] thing = [a: int, ~middle, c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"foo = int middle = [foo] thing = [a: int, ~middle, c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"header = [a: int] thing = [~header, c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"footer = [a: int] thing = [c: int, ~footer]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"footer = [a: int, b: int] thing = [c: int, d: int, ~footer]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"thing = [c: int ~footer]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
let cddl_input = r#"header = {a: int, b: int} thing = [~header c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
}
#[test]
fn validate_json_array_record() {
let cddl_input = r#"thing = [a: int, b: int, c: int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
validate_json_str("thing", cddl_input, "[]").unwrap_err();
let cddl_input = r#"thing = [a: int, b: int, c: foo] foo = int"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
let cddl_input = r#"thing = [int, int, int]"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap();
validate_json_str("thing", cddl_input, "[]").unwrap_err();
let cddl_input = r#"thing = [a: tstr, b: int]"#;
let input = PersonTuple("Alice".to_string(), 42);
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap();
let input = BackwardsTuple(43, "Carol".to_string());
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let input = LongTuple("David".to_string(), 44, 45);
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let input = ShortTuple("Eve".to_string());
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = [a: tstr, b: uint, c: float, d: bool]"#;
let input = KitchenSink("xyz".to_string(), 17, 9.9, false);
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("thing", cddl_input, &json_str).unwrap();
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
}
#[test]
fn validate_json_map_unwrap() {
let input = PersonStruct {
name: "Bob".to_string(),
age: 43,
};
let json_str = serde_json::to_string(&input).unwrap();
let cddl_input = r#"thing = {name: tstr, ~agroup} agroup = {age: int}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, ~agroup} agroup = [age: int]"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
}
#[test]
fn validate_json_map_group() {
let input = PersonStruct {
name: "Bob".to_string(),
age: 43,
};
let json_str = serde_json::to_string(&input).unwrap();
let cddl_input = r#"thing = {name: tstr, agroup} agroup = (age: int)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {agroup} agroup = (age: int, name: tstr)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {((agroup))} agroup = (age: int, name: tstr)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {agroup empty} agroup = (age: int, name: tstr) empty = ()"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input =
r#"thing = {agroup maybe} agroup = (age: int, name: tstr) maybe = (? minor: bool)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, agroup} agroup = (wrong: int)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {name: tstr, agroup} agroup = (age: bool)"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
}
#[test]
fn validate_json_map() {
let input = PersonStruct {
name: "Bob".to_string(),
age: 43,
};
let json_str = serde_json::to_string(&input).unwrap();
let cddl_input = r#"thing = {name: tstr, age: int}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, ? age: int}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, age: int, ? minor: bool}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, age: int, * minor: bool}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, age: int, + minor: bool}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {name: tstr, age: tstr}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {name: tstr}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {* tstr => any}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, * tstr => any}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {name: tstr, age: int, * tstr => any}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {+ tstr => any}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap();
let cddl_input = r#"thing = {* int => any}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {name: tstr, age: int, minor: bool}"#;
validate_json_str("thing", cddl_input, &json_str).unwrap_err();
let cddl_input = r#"thing = {x: int, y: int, z: int}"#;
validate_json_str("thing", cddl_input, "[1, 2, 3]").unwrap_err();
}
#[test]
fn validate_json_map_cut() {
let json_str = r#"{ "foo": "not-an-int" }"#;
let cddl = r#"
thing = {
? "foo" => int, ; non-cut is the default for "=>"
tstr => tstr,
}"#;
validate_json_str("thing", cddl, &json_str).unwrap();
let cddl = r#"
thing = {
? "foo" ^ => int, ; cut is indicated by "^"
tstr => tstr,
}"#;
let err = validate_json_str("thing", cddl, &json_str).unwrap_err();
assert_eq!(err.to_string(), "Mismatch(expected int)");
let cddl = r#"
thing = {
? "foo": int, ; cut is implied by ":"
tstr => tstr,
}"#;
validate_json_str("thing", cddl, &json_str).unwrap_err();
let json_str = r#"{ "foo": 17, "bar": "baz" }"#;
let cddl = r#"
thing = {
? "foo" => int,
tstr => tstr,
}"#;
validate_json_str("thing", cddl, &json_str).unwrap();
let cddl = r#"
thing = {
tstr => tstr,
? "foo" => int,
}"#;
validate_json_str("thing", cddl, &json_str).unwrap();
let cddl = r#"thing = { "foo": int // tstr => tstr }"#;
let json_str = r#"{ "foo": "not-int" }"#;
validate_json_str("thing", cddl, &json_str).unwrap();
let json_str = r#"{ "aaa": 17, "zzz": "baz" }"#;
let cddl = r#"thing = {* tstr ^ => int }"#;
let err = validate_json_str("thing", cddl, &json_str).unwrap_err();
assert_eq!(err.to_string(), "Mismatch(expected int)");
}
#[derive(Debug, Serialize)]
struct StreetNumber {
street: String,
number: u32,
name: String,
zip_code: u32,
}
#[derive(Debug, Serialize)]
struct POBox {
po_box: u32,
name: String,
zip_code: u32,
}
#[derive(Debug, Serialize)]
struct Pickup {
per_pickup: bool,
}
#[test]
fn validate_choice_example() {
let cddl_input = r#"
address = { delivery }
delivery = (
street: tstr, ? number: uint, city //
po_box: uint, city //
per_pickup: true )
city = (
name: tstr, zip_code: uint
)"#;
let input = POBox {
po_box: 101,
name: "San Francisco".to_string(),
zip_code: 94103,
};
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("address", cddl_input, &json_str).unwrap();
let input = StreetNumber {
street: "Eleventh St.".to_string(),
number: 375,
name: "San Francisco".to_string(),
zip_code: 94103,
};
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("address", cddl_input, &json_str).unwrap();
let json_str = r#"{
"street": "Eleventh St.",
"name": "San Francisco",
"zip_code": 94103
}"#;
validate_json_str("address", cddl_input, &json_str).unwrap();
let input = Pickup { per_pickup: true };
let json_str = serde_json::to_string(&input).unwrap();
validate_json_str("address", cddl_input, &json_str).unwrap();
}