#![feature(custom_derive, plugin, test)] #![feature(custom_attribute)] #![plugin(serde_macros)] #[macro_use] extern crate log; extern crate test; extern crate serde; extern crate serde_xml; extern crate glob; use std::fmt::Debug; use serde_xml::from_str; use serde_xml::value::{Element, from_value}; use serde_xml::Error; use serde::de; use serde::ser; #[derive(PartialEq, Debug, Serialize, Deserialize)] enum Animal { Dog, Frog(String), Ant(Simple), Cat { age: usize, name: String }, } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct Simple { a: (), b: usize, c: String, d: Option, } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct Inner { a: (), b: (usize, String, i8), c: Vec, } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct Outer { inner: Option, } fn test_parse_ok<'a, T>(errors: &[(&'a str, T)]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize, { for &(s, ref value) in errors { let v: T = from_str(s).unwrap(); assert_eq!(v, *value); // Make sure we can deserialize into an `Element`. let xml_value: Element = from_str(s).unwrap(); // Make sure we can deserialize from an `Element`. let v: T = from_value(xml_value.clone()).unwrap(); assert_eq!(v, *value); } } fn test_parse_err<'a, T>(errors: &[&'a str]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize, { for &s in errors { assert!(match from_str::(s) { Err(Error::SyntaxError(..)) => true, _ => false, }); } } #[test] fn test_namespaces() { init_logger(); #[derive(PartialEq, Serialize, Deserialize, Debug)] struct Envelope { subject: String, } let s = r#" Reference rates "#; test_parse_ok(&[ ( s, Envelope { subject: "Reference rates".to_string(), }, ), ]); } #[test] fn test_doctype() { init_logger(); #[derive(PartialEq, Serialize, Deserialize, Debug)] struct Envelope { subject: String, } test_parse_ok(&[ ( r#" Reference rates "#, Envelope { subject: "Reference rates".to_string(), }, ), ( r#" Reference rates "#, Envelope { subject: "Reference rates".to_string(), }, ), ( r#" ] > Reference rates "#, Envelope { subject: "Reference rates".to_string(), }, ), ]); } #[test] fn test_doctype_fail() { init_logger(); #[derive(PartialEq, Serialize, Deserialize, Debug)] struct Envelope { subject: String, } test_parse_err::(&[r#" > Reference rates "#, r#" Reference rates ]> "#, ]) } #[test] fn test_forwarded_namespace() { #[derive(PartialEq, Serialize, Deserialize, Debug)] struct Graphml { #[serde(rename="xsi:schemaLocation")] schema_location: String } let s = r#" "#; test_parse_ok(&[ ( s, Graphml { schema_location: "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd".to_string() }, ), ]); } #[test] fn test_parse_string() { init_logger(); test_parse_ok(&[ ( "This is a String", "This is a String".to_string(), ), ( "", "".to_string(), ), ( " ", " ".to_string(), ), ( "<boom/>", "".to_string(), ), ( "", "♫".to_string(), ), ( "", "♫".to_string(), ), ( "]]>♫", "♫♫".to_string(), ) ]); } fn init_logger() { use log::{LogRecord, LogLevel, LogMetadata}; struct SimpleLogger; impl log::Log for SimpleLogger { fn enabled(&self, metadata: &LogMetadata) -> bool { metadata.level() <= LogLevel::Debug } fn log(&self, record: &LogRecord) { if self.enabled(record.metadata()) { println!("{} - {}", record.level(), record.args()); } } } let _ = log::set_logger(|max_log_level| { max_log_level.set(log::LogLevelFilter::Debug); Box::new(SimpleLogger) }); } #[test] fn test_parse_enum() { use self::Animal::*; init_logger(); init_logger(); test_parse_ok(&[ ("", Dog), ("Quak", Frog("Quak".to_string())), ("bla15Foo", Ant(Simple{ a: (), b: 15, c: "bla".to_string(), d: Some("Foo".to_string()), })), ("bla15", Ant(Simple{ a: (), b: 15, c: "bla".to_string(), d: None, })), ( "42Shere Khan", Cat { age: 42, name: "Shere Khan".to_string(), }, ), ]); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct Helper { x: Animal, } test_parse_ok(&[ ( "", Helper { x: Dog }, ), ( "Quak", Helper { x: Frog("Quak".to_string()) }, ), ( " 42 Shere Khan ", Helper { x: Cat { age: 42, name: "Shere Khan".to_string(), } }, ), ]); } #[test] fn test_parse_i64() { init_logger(); test_parse_ok(&[ ("0", 0), ("-2", -2), ("-1234", -1234), (" -1234 ", -1234), ]); } #[test] fn test_parse_u64() { init_logger(); test_parse_ok(&[ ("0", 0), ("1234", 1234), (" 1234 ", 1234), ]); } #[test] fn test_parse_bool() { test_parse_ok(&[ ("true", true), ("false", false), (" true ", true), (" false ", false), ]); } #[test] fn test_parse_unit() { init_logger(); test_parse_ok(&[ ("", ()), ]); } #[test] fn test_parse_f64() { init_logger(); test_parse_ok(&[ ("3.0", 3.0f64), ("3.1", 3.1), ("-1.2", -1.2), ("0.4", 0.4), ("0.4e5", 0.4e5), ("0.4e15", 0.4e15), //("0.4e-01", 0.4e-01), // precision troubles //(" 0.4e-01 ", 0.4e-01), ]); } #[test] fn test_parse_struct() { init_logger(); test_parse_ok(&[ ( " abc 2 ", Simple { a: (), b: 2, c: "abc".to_string(), d: None, }, ), ( " abc 2 ", Simple { a: (), b: 2, c: "abc".to_string(), d: None, }, ), ( " abc 2 ", Simple { a: (), b: 2, c: "abc".to_string(), d: Some("Foo".to_string()), }, ), ]); } #[test] fn test_option() { init_logger(); test_parse_ok(&[ ("", Some("".to_string())), ("", Some("".to_string())), (" ", Some(" ".to_string())), ("42", Some("42".to_string())), ]); } #[test] fn test_amoskvin() { init_logger(); #[derive(Debug, Deserialize, PartialEq, Serialize)] struct Root { foo: Vec, } #[derive(Debug, Deserialize, PartialEq, Serialize)] struct Foo { a: String, b: Option, } test_parse_ok(&[ ( " Hello World Hi ", Root { foo: vec![ Foo { a: "Hello".to_string(), b: Some("World".to_string()), }, Foo { a: "Hi".to_string(), b: None, } ] } ), ]); } #[test] fn test_nicolai86() { init_logger(); #[derive(Serialize, Deserialize, PartialEq, Debug)] struct TheSender { name: String, } #[derive(Serialize, Deserialize, PartialEq, Debug)] struct CurrencyCube { currency: String, rate: String, } #[derive(Serialize, Deserialize, PartialEq, Debug)] #[allow(non_snake_case)] struct InnerCube { Cube: Vec, } #[derive(Serialize, Deserialize, PartialEq, Debug)] #[allow(non_snake_case)] struct OuterCube { Cube: Vec, } #[derive(Serialize, Deserialize, PartialEq, Debug)] #[allow(non_snake_case)] struct Envelope { subject: String, Sender: TheSender, Cube: OuterCube, } test_parse_ok(&[ ( r#" Reference rates European Central Bank "#, Envelope { subject: "Reference rates".to_string(), Sender: TheSender { name: "European Central Bank".to_string(), }, Cube: OuterCube { Cube: vec![], } }, ), ( r#" Reference rates European Central Bank "#, Envelope { subject: "Reference rates".to_string(), Sender: TheSender { name: "European Central Bank".to_string(), }, Cube: OuterCube { Cube: vec![InnerCube { Cube: vec![ CurrencyCube { currency: "GBP".to_string(), rate: "0.81725".to_string(), }, CurrencyCube { currency: "Latinum".to_string(), rate: "999999".to_string(), }, ], }], } }, ), ]); } #[test] fn test_hugo_duncan2() { init_logger(); let s = r#" 8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1 vpc-ba0d18d8 available "#; #[derive(PartialEq, Debug, Serialize, Deserialize)] #[allow(non_snake_case)] struct VpcSet { vpcId: String, state: String, } #[derive(PartialEq, Debug, Serialize)] struct ItemVec(Vec); impl de::Deserialize for ItemVec { fn deserialize(deserializer: &mut D) -> Result, D::Error> where D: de::Deserializer, { #[derive(PartialEq, Debug, Serialize, Deserialize)] struct Helper { item: Vec, } let h: Helper<_> = try!(de::Deserialize::deserialize(deserializer)); Ok(ItemVec(h.item)) } } #[derive(PartialEq, Debug, Serialize, Deserialize)] #[allow(non_snake_case)] struct DescribeVpcsResponse { requestId: String, vpcSet: ItemVec, } test_parse_ok(&[ ( s, DescribeVpcsResponse { requestId: "8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1".to_string(), vpcSet: ItemVec(vec![ VpcSet { vpcId: "vpc-ba0d18d8".to_string(), state: "available".to_string(), }]), }, ), ]); } #[test] fn test_hugo_duncan() { init_logger(); let s = " 9474f558-10a5-42e8-84d1-f9ee181fe943 "; #[derive(PartialEq, Debug, Serialize, Deserialize)] #[allow(non_snake_case)] struct DescribeInstancesResponse { requestId: String, reservationSet: (), } test_parse_ok(&[ ( s, DescribeInstancesResponse { requestId: "9474f558-10a5-42e8-84d1-f9ee181fe943".to_string(), reservationSet: (), }, ), ]); } #[test] fn test_parse_xml_value() { init_logger(); #[derive(Eq, Debug, PartialEq, Deserialize, Serialize)] struct Test { #[serde(rename="$value")] myval: String, } test_parse_ok(&[ ( "abc", Test { myval: "abc".to_string() }, ) ]); } #[test] fn test_parse_complexstruct() { init_logger(); test_parse_ok(&[ ( " 2 boom 88 ", Outer { inner: Some(Inner { a: (), b: (2, "boom".to_string(), 88), c: vec![] }) }, ), ( " abc xyz 2 boom 88 ", Outer { inner: Some(Inner { a: (), b: (2, "boom".to_string(), 88), c: vec![ "abc".to_string(), "xyz".to_string(), ] }) }, ), ( "", Outer { inner: None }, ) ]); } #[test] fn test_parse_attributes() { init_logger(); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct A { a1: String, #[serde(rename="$value")] a2: i32, } test_parse_ok(&[ ( r#"42"#, A { a1: "What is the answer to the ultimate question?".to_string(), a2: 42, } ), ]); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct B { b1: String, b2: i32, } test_parse_ok(&[ ( r#""#, B { b1: "What is the answer to the ultimate question?".to_string(), b2: 42, } ), ]); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct C { c1: B, } test_parse_ok(&[ ( r#""#, C { c1: B { b1: "What is the answer to the ultimate question?".to_string(), b2: 42, }} ), ( r#" "#, C { c1: B { b1: "What is the answer to the ultimate question?".to_string(), b2: 42, }} ), ( r#" "#, C { c1: B { b1: "What is the answer to the ultimate question?".to_string(), b2: 42, }} ), ]); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct D { d1: Option, } test_parse_ok(&[ ( r#"42"#, D { d1: Some( A { a1: "What is the answer to the ultimate question?".to_string(), a2: 42, } ) } ), ]); } #[test] fn test_parse_hierarchies() { init_logger(); #[derive(PartialEq, Debug, Serialize, Deserialize)] struct A { a1: String, a2: (String, String), } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct B { b1: A, b2: (A, A), } #[derive(PartialEq, Debug, Serialize, Deserialize)] struct C { c1: B, c2: Vec, } test_parse_ok(&[ ( " No Maybe Yes Red Green Blue London Berlin Paris ", C { c1: B { b1: A { a1: "No".to_string(), a2: ("Maybe".to_string(), "Yes".to_string()), }, b2: (A { a1: "Red".to_string(), a2: ("Green".to_string(), "Blue".to_string()), }, A { a1: "London".to_string(), a2: ("Berlin".to_string(), "Paris".to_string()), }, ), }, c2: vec![] } ), ( " Green Blue Red Berlin Paris London Maybe Yes No ", C { c1: B { b1: A { a1: "No".to_string(), a2: ("Maybe".to_string(), "Yes".to_string()), }, b2: (A { a1: "Red".to_string(), a2: ("Green".to_string(), "Blue".to_string()), }, A { a1: "London".to_string(), a2: ("Berlin".to_string(), "Paris".to_string()), }, ), }, c2: vec![] } ), ]); } #[test] fn unknown_field() { #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)] struct A { other: Vec, } #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)] struct Other { d: i32, } test_parse_ok(&[ ( " 5 6 ", A { other: vec![ Other { d: 6, }, ] }, ) ]); } #[test] fn eoz() { use std::io::Read; let mut file = std::fs::File::open("Report_test.2.xml").unwrap(); let mut s = String::new(); file.read_to_string(&mut s).unwrap(); let _xml_value: Element = from_str(&s).unwrap(); } #[test] fn test_parse_unfinished() { test_parse_err::(&[ " abc 2 ", ]); } #[test] fn test_things_qc_found() { test_parse_err::(&[ "<\u{0}:/", ]); } #[test] fn futile() { init_logger(); #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] struct Object { id: u8, name: String, x: u8, y: u8, width: u8, height: u8, ellipse: Option<()>, } test_parse_ok(&[ ( r###" "###, Object { id: 11, name: "testEllipse".to_owned(), x: 102, y: 38, width: 21, height: 14, ellipse: Some(()), }, ), ( r###" "###, Object { id: 11, name: "testEllipse".to_owned(), x: 102, y: 38, width: 21, height: 14, ellipse: None, }, ), ]); } #[test] fn futile2() { init_logger(); #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] struct Null; #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] struct Object { field: Option, }; #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)] struct Stuff { stuff_field: Option, }; test_parse_ok(&[ ( r###" "###, Object { field: Some(Null), }, ), ( r###" "###, Object { field: None, }, ), ]); test_parse_ok(&[ ( r###" "###, Stuff { stuff_field: Some(Object { field: None, }), }, ), ( r###" "###, Stuff { stuff_field: Some(Object { field: Some(Null), }), }, ), ( r###" "###, Stuff { stuff_field: None, }, ), ( r###" "###, Stuff { stuff_field: None, }, ), ]); }