blob: c67712e9c811f8b0f7f80f2a513e70195c429e92 [file] [log] [blame]
mod common;
use common::init_logger;
use serde::{de, ser, Deserialize, Serialize};
use serde_xml_rs::{from_str, Error};
use std::fmt::Debug;
#[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<String>,
}
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Inner {
a: (),
b: (usize, String, i8),
c: Vec<String>,
}
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Outer {
inner: Option<Inner>,
}
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::<T>(s) {
Err(Error::Syntax { source: _ }) => true,
_ => false,
});
}
}
#[test]
fn test_namespaces() {
init_logger();
#[derive(PartialEq, Serialize, Deserialize, Debug)]
struct Envelope {
subject: String,
}
let s = r#"
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
</gesmes:Envelope>"#;
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#"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Envelope>
<Envelope>
<subject>Reference rates</subject>
</Envelope>"#,
Envelope {
subject: "Reference rates".to_string(),
},
),
(
r#"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Envelope[]>
<Envelope>
<subject>Reference rates</subject>
</Envelope>"#,
Envelope {
subject: "Reference rates".to_string(),
},
),
(
r#"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Envelope [
<!ELEMENT subject (#PCDATA)>
] >
<Envelope>
<subject>Reference rates</subject>
</Envelope>"#,
Envelope {
subject: "Reference rates".to_string(),
},
),
]);
}
#[test]
#[ignore] // FIXME
fn test_forwarded_namespace() {
#[derive(PartialEq, Serialize, Deserialize, Debug)]
struct Graphml {
#[serde(rename = "xsi:schemaLocation")]
schema_location: String,
}
let s = r#"
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
</graphml>"#;
test_parse_ok(&[(
s,
Graphml {
schema_location: "http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"
.to_string(),
},
)]);
}
#[test]
#[ignore] // FIXME
fn test_parse_string_not_trim() {
init_logger();
test_parse_ok(&[("<bla> </bla>", " ".to_string())]);
}
#[test]
#[ignore] // FIXME
fn test_parse_enum() {
use self::Animal::*;
init_logger();
test_parse_ok(&[
("<Animal xsi:type=\"Dog\"/>", Dog),
(
"<Animal xsi:type=\"Frog\">Quak</Animal>",
Frog("Quak".to_string()),
),
(
"<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b><d>Foo</d></Animal>",
Ant(Simple {
a: (),
b: 15,
c: "bla".to_string(),
d: Some("Foo".to_string()),
}),
),
(
"<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b></Animal>",
Ant(Simple {
a: (),
b: 15,
c: "bla".to_string(),
d: None,
}),
),
(
"<Animal xsi:type=\"Cat\"><age>42</age><name>Shere Khan</name></Animal>",
Cat {
age: 42,
name: "Shere Khan".to_string(),
},
),
]);
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Helper {
x: Animal,
}
test_parse_ok(&[
("<Helper><x xsi:type=\"Dog\"/></Helper>", Helper { x: Dog }),
(
"<Helper><x xsi:type=\"Frog\">Quak</Animal></Helper>",
Helper {
x: Frog("Quak".to_string()),
},
),
(
"<Helper><x xsi:type=\"Cat\">
<age>42</age>
<name>Shere Khan</name>
</x></Helper>",
Helper {
x: Cat {
age: 42,
name: "Shere Khan".to_string(),
},
},
),
]);
}
#[test]
fn test_parse_struct() {
init_logger();
test_parse_ok(&[
(
"<Simple>
<c>abc</c>
<a/>
<b>2</b>
</Simple>",
Simple {
a: (),
b: 2,
c: "abc".to_string(),
d: None,
},
),
(
"<Simple><!-- this is a comment -->
<c>abc</c>
<a/>
<b>2</b>
</Simple>",
Simple {
a: (),
b: 2,
c: "abc".to_string(),
d: None,
},
),
(
"<Simple d=\"Foo\"><!-- this is a comment -->
<c>abc</c>
<a/>
<b>2</b>
</Simple>",
Simple {
a: (),
b: 2,
c: "abc".to_string(),
d: Some("Foo".to_string()),
},
),
]);
}
#[test]
#[ignore] // FIXME
fn test_option_not_trim() {
init_logger();
test_parse_ok(&[("<a> </a>", Some(" ".to_string()))]);
}
#[test]
fn test_amoskvin() {
init_logger();
#[derive(Debug, Deserialize, PartialEq, Serialize)]
struct Root {
foo: Vec<Foo>,
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
struct Foo {
a: String,
b: Option<String>,
}
test_parse_ok(&[(
"
<root>
<foo>
<a>Hello</a>
<b>World</b>
</foo>
<foo>
<a>Hi</a>
</foo>
</root>",
Root {
foo: 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<CurrencyCube>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[allow(non_snake_case)]
struct OuterCube {
Cube: Vec<InnerCube>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[allow(non_snake_case)]
struct Envelope {
subject: String,
Sender: TheSender,
Cube: OuterCube,
}
test_parse_ok(&[
(
r#"
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube> </Cube>
</gesmes:Envelope>"#,
Envelope {
subject: "Reference rates".to_string(),
Sender: TheSender {
name: "European Central Bank".to_string(),
},
Cube: OuterCube { Cube: vec![] },
},
),
(
r#"
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube><Cube>
<Cube currency='GBP' rate='0.81725'/>
<Cube currency='Latinum' rate='999999'/>
</Cube></Cube>
</gesmes:Envelope>"#,
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#"
<?xml version="1.0" encoding="UTF-8"?>
<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
<requestId>8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1</requestId>
<vpcSet>
<item>
<vpcId>vpc-ba0d18d8</vpcId>
<state>available</state>
</item>
</vpcSet>
</DescribeVpcsResponse>"#;
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
struct VpcSet {
vpcId: String,
state: String,
}
#[derive(PartialEq, Debug, Serialize)]
struct ItemVec<T>(Vec<T>);
impl<'de, T: de::Deserialize<'de>> de::Deserialize<'de> for ItemVec<T> {
fn deserialize<D>(deserializer: D) -> Result<ItemVec<T>, D::Error>
where
D: de::Deserializer<'de>,
{
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Helper<U> {
item: Vec<U>,
}
let h: Helper<_> = de::Deserialize::deserialize(deserializer)?;
Ok(ItemVec(h.item))
}
}
#[derive(PartialEq, Debug, Serialize, Deserialize)]
#[allow(non_snake_case)]
struct DescribeVpcsResponse {
requestId: String,
vpcSet: ItemVec<VpcSet>,
}
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 = "
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<DescribeInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2014-10-01/\">
<requestId>9474f558-10a5-42e8-84d1-f9ee181fe943</requestId>
<reservationSet/>
</DescribeInstancesResponse>
";
#[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(&[(
"<Test>abc</Test>",
Test {
myval: "abc".to_string(),
},
)]);
}
#[test]
#[ignore] // FIXME
fn test_parse_complexstruct() {
init_logger();
test_parse_ok(&[
(
"<Outer>
<inner>
<b>2</b>
<b>boom</b>
<b>88</b>
</inner>
</Outer>",
Outer {
inner: Some(Inner {
a: (),
b: (2, "boom".to_string(), 88),
c: vec![],
}),
},
),
(
"<Outer>
<inner>
<c>abc</c>
<c>xyz</c>
<a/>
<b>2</b>
<b>boom</b>
<b>88</b>
</inner>
</Outer>",
Outer {
inner: Some(Inner {
a: (),
b: (2, "boom".to_string(), 88),
c: vec!["abc".to_string(), "xyz".to_string()],
}),
},
),
("<Outer/>", 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#"<A a1="What is the answer to the ultimate question?">42</A>"#,
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?" b2="42"/>"#,
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 b1="What is the answer to the ultimate question?" b2="42"/></C>"#,
C {
c1: B {
b1: "What is the answer to the ultimate question?".to_string(),
b2: 42,
},
},
),
(
r#"<C><c1 b1="What is the answer to the ultimate question?" b2="42"/> </C>"#,
C {
c1: B {
b1: "What is the answer to the ultimate question?".to_string(),
b2: 42,
},
},
),
(
r#"<C> <c1 b1="What is the answer to the ultimate question?" b2="42">
</c1> </C>"#,
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<A>,
}
test_parse_ok(&[(
r#"<D><d1 a1="What is the answer to the ultimate question?">42</d1></D>"#,
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<B>,
}
test_parse_ok(&[
(
"<C><c1>
<b1>
<a1>No</a1>
<a2>Maybe</a2>
<a2>Yes</a2>
</b1>
<b2>
<a1>Red</a1>
<a2>Green</a2>
<a2>Blue</a2>
</b2>
<b2>
<a1>London</a1>
<a2>Berlin</a2>
<a2>Paris</a2>
</b2>
</c1></C>",
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![],
},
),
(
"<C><c1>
<b2>
<a2>Green</a2>
<a2>Blue</a2>
<a1>Red</a1>
</b2>
<b2>
<a2>Berlin</a2>
<a2>Paris</a2>
<a1>London</a1>
</b2>
<b1>
<a2>Maybe</a2>
<a2>Yes</a2>
<a1>No</a1>
</b1>
</c1></C>",
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<Other>,
}
#[derive(Deserialize, Debug, PartialEq, Eq, Serialize)]
struct Other {
d: i32,
}
test_parse_ok(&[(
"<a>
<b>
<c>5</c>
</b>
<other>
<d>6</d>
</other>
</a>",
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::<Simple>(&["<Simple>
<c>abc</c>
<a/>
<b>2</b>
<d/>"]);
}
#[test]
fn test_things_qc_found() {
test_parse_err::<u32>(&["<\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" x="102" y="38" width="21" height="14">
<ellipse/>
</object>
"###,
Object {
id: 11,
name: "testEllipse".to_owned(),
x: 102,
y: 38,
width: 21,
height: 14,
ellipse: Some(()),
},
),
(
r###"
<object id="11" name="testEllipse" x="102" y="38" width="21" height="14">
</object>
"###,
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<Null>,
}
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
struct Stuff {
stuff_field: Option<Object>,
}
test_parse_ok(&[
(
r###"
<object>
<field/>
</object>
"###,
Object { field: Some(Null) },
),
(
r###"
<object>
</object>
"###,
Object { field: None },
),
]);
test_parse_ok(&[
(
r###"
<object>
<stuff_field/>
</object>
"###,
Stuff {
stuff_field: Some(Object { field: None }),
},
),
(
r###"
<object>
<stuff_field>
<field/>
</stuff_field>
</object>
"###,
Stuff {
stuff_field: Some(Object { field: Some(Null) }),
},
),
(
r###"
<object>
</object>
"###,
Stuff { stuff_field: None },
),
(
r###"
<object/>
"###,
Stuff { stuff_field: None },
),
]);
}
#[test]
fn newtype_struct() {
#[derive(PartialEq, Debug, Serialize, Deserialize)]
struct Wrapper(String);
test_parse_ok(&[(
r###"<wrapper>Content</wrapper>"###,
Wrapper("Content".into()),
)]);
}