1053 lines
26 KiB
Rust
1053 lines
26 KiB
Rust
use simple_logger::SimpleLogger;
|
|
use std::fmt::Debug;
|
|
|
|
use serde::{de, ser};
|
|
use serde_derive::{Deserialize, Serialize};
|
|
use serde_xml_rs::{from_str, Error};
|
|
|
|
fn init_logger() {
|
|
let _ = SimpleLogger::new().init();
|
|
}
|
|
|
|
#[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,
|
|
});
|
|
}
|
|
}
|
|
|
|
fn test_parse_invalid<'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(_) => 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]
|
|
fn test_parse_string() {
|
|
init_logger();
|
|
|
|
test_parse_ok(&[
|
|
(
|
|
"<bla>This is a String</bla>",
|
|
"This is a String".to_string(),
|
|
),
|
|
("<bla></bla>", "".to_string()),
|
|
("<bla> </bla>", "".to_string()),
|
|
("<bla><boom/></bla>", "<boom/>".to_string()),
|
|
("<bla>♫</bla>", "♫".to_string()),
|
|
("<bla>♫</bla>", "♫".to_string()),
|
|
(
|
|
"<bla>♫<![CDATA[<cookies/>]]>♫</bla>",
|
|
"♫<cookies/>♫".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_i64() {
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<bla>0</bla>", 0),
|
|
("<bla>-2</bla>", -2),
|
|
("<bla>-1234</bla>", -1234),
|
|
("<bla> -1234 </bla>", -1234),
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_u64() {
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<bla>0</bla>", 0),
|
|
("<bla>1234</bla>", 1234),
|
|
("<bla> 1234 </bla>", 1234),
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_bool_element() {
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<bla>true</bla>", true),
|
|
("<bla>false</bla>", false),
|
|
("<bla> true </bla>", true),
|
|
("<bla> false </bla>", false),
|
|
("<bla>1</bla>", true),
|
|
("<bla>0</bla>", false),
|
|
]);
|
|
|
|
test_parse_invalid::<bool>(&["<bla>verum</bla>"]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_bool_attribute() {
|
|
#[derive(PartialEq, Debug, Deserialize, Serialize)]
|
|
struct Dummy {
|
|
foo: bool,
|
|
}
|
|
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<bla foo=\"true\"/>", Dummy { foo: true }),
|
|
("<bla foo=\"false\"/>", Dummy { foo: false }),
|
|
("<bla foo=\"1\"/>", Dummy { foo: true }),
|
|
("<bla foo=\"0\"/>", Dummy { foo: false }),
|
|
]);
|
|
|
|
test_parse_invalid::<Dummy>(&[
|
|
"<bla foo=\"bar\"/>",
|
|
"<bla foo=\" true \"/>",
|
|
"<bla foo=\"10\"/>",
|
|
"<bla foo=\"\"/>",
|
|
"<bla/>",
|
|
]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_unit() {
|
|
init_logger();
|
|
test_parse_ok(&[("<bla/>", ())]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_f64() {
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<bla>3.0</bla>", 3.0f64),
|
|
("<bla>3.1</bla>", 3.1),
|
|
("<bla>-1.2</bla>", -1.2),
|
|
("<bla>0.4</bla>", 0.4),
|
|
("<bla>0.4e5</bla>", 0.4e5),
|
|
("<bla>0.4e15</bla>", 0.4e15),
|
|
("<bla>0.4e-01</bla>", 0.4e-01), // precision troubles
|
|
("<bla> 0.4e-01 </bla>", 0.4e-01),
|
|
]);
|
|
}
|
|
|
|
#[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]
|
|
fn test_option() {
|
|
init_logger();
|
|
test_parse_ok(&[
|
|
("<a/>", Some("".to_string())),
|
|
("<a></a>", Some("".to_string())),
|
|
("<a> </a>", Some("".to_string())),
|
|
("<a>42</a>", Some("42".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()),
|
|
)]);
|
|
}
|