#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde; extern crate serde_yaml; extern crate unindent; use unindent::unindent; use std::collections::BTreeMap; use std::fmt::Debug; use serde_yaml::Value; fn test_de(yaml: &str, expected: &T) where T: serde::de::DeserializeOwned + PartialEq + Debug, { let deserialized: T = serde_yaml::from_str(yaml).unwrap(); assert_eq!(*expected, deserialized); serde_yaml::from_str::(yaml).unwrap(); serde_yaml::from_str::(yaml).unwrap(); } #[test] fn test_alias() { let yaml = unindent( " --- first: &alias 1 second: *alias third: 3", ); let mut expected = BTreeMap::new(); { expected.insert(String::from("first"), 1); expected.insert(String::from("second"), 1); expected.insert(String::from("third"), 3); } test_de(&yaml, &expected); } #[test] fn test_option() { #[derive(Deserialize, PartialEq, Debug)] struct Data { a: Option, b: Option, c: Option, } let yaml = unindent( " --- b: c: true", ); let expected = Data { a: None, b: None, c: Some(true), }; test_de(&yaml, &expected); } #[test] fn test_option_alias() { #[derive(Deserialize, PartialEq, Debug)] struct Data { a: Option, b: Option, c: Option, d: Option, e: Option, f: Option, } let yaml = unindent( " --- none_f: &none_f ~ none_s: &none_s ~ none_b: &none_b ~ some_f: &some_f 1.0 some_s: &some_s x some_b: &some_b true a: *none_f b: *none_s c: *none_b d: *some_f e: *some_s f: *some_b", ); let expected = Data { a: None, b: None, c: None, d: Some(1.0), e: Some("x".to_owned()), f: Some(true), }; test_de(&yaml, &expected); } #[test] fn test_enum_alias() { #[derive(Deserialize, PartialEq, Debug)] enum E { A, B(u8, u8), } #[derive(Deserialize, PartialEq, Debug)] struct Data { a: E, b: E, } let yaml = unindent( " --- aref: &aref A bref: &bref B: - 1 - 2 a: *aref b: *bref", ); let expected = Data { a: E::A, b: E::B(1, 2), }; test_de(&yaml, &expected); } #[test] fn test_enum_tag() { #[derive(Deserialize, PartialEq, Debug)] enum E { A(String), B(String), } #[derive(Deserialize, PartialEq, Debug)] struct Data { a: E, b: E, } let yaml = unindent( " --- a: !A foo b: !B bar", ); let expected = Data { a: E::A("foo".into()), b: E::B("bar".into()), }; test_de(&yaml, &expected); } #[test] fn test_number_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { value: String, } let yaml = unindent( " --- # Cannot be represented as u128 value: 340282366920938463463374607431768211457", ); let expected = Num { value: "340282366920938463463374607431768211457".to_owned(), }; test_de(&yaml, &expected); } serde_if_integer128! { #[test] fn test_i128_big() { let expected: i128 = ::std::i64::MIN as i128 - 1; let yaml = unindent( " --- -9223372036854775809", ); assert_eq!(expected, serde_yaml::from_str::(&yaml).unwrap()); } #[test] fn test_u128_big() { let expected: u128 = ::std::u64::MAX as u128 + 1; let yaml = unindent( " --- 18446744073709551616", ); assert_eq!(expected, serde_yaml::from_str::(&yaml).unwrap()); } } #[test] fn test_number_alias_as_string() { #[derive(Deserialize, PartialEq, Debug)] struct Num { version: String, value: String, } let yaml = unindent( " --- version: &a 1.10 value: *a", ); let expected = Num { version: "1.10".to_owned(), value: "1.10".to_owned(), }; test_de(&yaml, &expected); } #[test] fn test_de_mapping() { #[derive(Debug, Deserialize, PartialEq)] struct Data { pub substructure: serde_yaml::Mapping, } let yaml = unindent( " --- substructure: a: 'foo' b: 'bar'", ); let mut expected = Data { substructure: serde_yaml::Mapping::new(), }; expected.substructure.insert( serde_yaml::Value::String("a".to_owned()), serde_yaml::Value::String("foo".to_owned()), ); expected.substructure.insert( serde_yaml::Value::String("b".to_owned()), serde_yaml::Value::String("bar".to_owned()), ); test_de(&yaml, &expected); } #[test] fn test_bomb() { #[derive(Debug, Deserialize, PartialEq)] struct Data { expected: String, } // This would deserialize an astronomical number of elements if we were // vulnerable. let yaml = unindent( " --- a: &a ~ b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a] c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b] d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c] e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d] f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e] g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f] h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g] i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h] j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i] k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j] l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k] m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l] n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m] o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n] p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o] q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p] r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q] s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r] t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s] u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t] v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u] w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v] x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w] y: &y [*x,*x,*x,*x,*x,*x,*x,*x,*x] z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y] expected: string", ); let expected = Data { expected: "string".to_owned(), }; assert_eq!(expected, serde_yaml::from_str::(&yaml).unwrap()); } #[test] fn test_numbers() { let cases = [ ("0xF0", "240"), ("+0xF0", "240"), ("-0xF0", "-240"), ("0o70", "56"), ("+0o70", "56"), ("-0o70", "-56"), ("0b10", "2"), ("+0b10", "2"), ("-0b10", "-2"), ("127", "127"), ("+127", "127"), ("-127", "-127"), (".inf", ".inf"), (".Inf", ".inf"), (".INF", ".inf"), ("-.inf", "-.inf"), ("-.Inf", "-.inf"), ("-.INF", "-.inf"), (".nan", ".nan"), (".NaN", ".nan"), (".NAN", ".nan"), ("0.1", "0.1"), ]; for &(yaml, expected) in &cases { let value = serde_yaml::from_str::(yaml).unwrap(); match value { Value::Number(number) => assert_eq!(number.to_string(), expected), _ => panic!("expected number"), } } }