#[macro_use] extern crate serde_derive; extern crate log; extern crate serde; extern crate serde_xml_rs; use std::fmt::Debug; use serde_xml_rs::{from_str, Error, ErrorKind}; use serde::{de, ser}; fn init_logger() { use log::{LogLevel, LogMetadata, LogRecord}; 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) }); } #[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<'de, 'a, T>(errors: &[(&'a str, T)]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>, { 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<'de, 'a, T>(errors: &[&'a str]) where T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>, { for &s in errors { assert!(match from_str::(s) { Err(Error(ErrorKind::Syntax(_), _)) => 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] #[ignore] // FIXME 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] #[ignore] // FIXME 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(), ), ]); } #[test] #[ignore] // FIXME fn test_parse_string_not_trim() { init_logger(); test_parse_ok(&[(" ", " ".to_string())]); } #[test] #[ignore] // FIXME fn test_parse_enum() { use self::Animal::*; 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] #[ignore] // FIXME fn test_option_not_trim() { init_logger(); test_parse_ok(&[(" ", Some(" ".to_string()))]); } #[test] fn test_amoskvin() { init_logger(); #[derive(Debug, Deserialize, PartialEq, Serialize)] struct Root { foos: Vec, } #[derive(Debug, Deserialize, PartialEq, Serialize)] struct Foo { a: String, b: Option, } test_parse_ok(&[ ( " Hello World Hi ", Root { foos: vec![ Foo { a: "Hello".to_string(), b: Some("World".to_string()), }, Foo { a: "Hi".to_string(), b: None, }, ], }, ), ]); } #[test] #[ignore] // FIXME 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 Vpc { vpcId: String, state: String, } #[derive(PartialEq, Debug, Serialize, Deserialize)] #[allow(non_snake_case)] struct DescribeVpcsResponse { requestId: String, vpcSet: Vec, } test_parse_ok(&[ ( s, DescribeVpcsResponse { requestId: "8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1".to_string(), vpcSet: vec![ Vpc { 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] #[ignore] // FIXME 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] #[ignore] // FIXME 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 }, ), ]); }