#[macro_use]
extern crate yaserde;
#[macro_use]
extern crate yaserde_derive;
use log::debug;
use std::io::Read;
use yaserde::de::from_str;
use yaserde::YaDeserialize;
fn init() {
let _ = env_logger::builder().is_test(true).try_init();
}
macro_rules! convert_and_validate {
($content: expr, $struct: tt, $model: expr) => {
debug!("convert_and_validate @ {}:{}", file!(), line!());
let loaded: Result<$struct, String> = from_str($content);
assert_eq!(loaded, Ok($model));
};
}
#[test]
fn de_basic() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
author: String,
title: String,
}
let content =
"Antoine de Saint-ExupéryLittle prince";
convert_and_validate!(
content,
Book,
Book {
author: "Antoine de Saint-Exupéry".to_owned(),
title: "Little prince".to_owned(),
}
);
let content =
"Little princeAntoine de Saint-Exupéry";
convert_and_validate!(
content,
Book,
Book {
author: "Antoine de Saint-Exupéry".to_owned(),
title: "Little prince".to_owned(),
}
);
}
#[test]
fn de_keyword() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
#[yaserde(attribute = true, rename = "ref")]
pub r#ref: String,
}
let content = "";
convert_and_validate!(
content,
Book,
Book {
r#ref: "978-1522968122".to_string()
}
);
}
#[test]
fn de_dash_param() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
#[yaserde(rename = "author-release")]
author: String,
title: String,
}
let content =
"Antoine de Saint-ExupéryLittle prince";
convert_and_validate!(
content,
Book,
Book {
author: "Antoine de Saint-Exupéry".to_owned(),
title: "Little prince".to_owned(),
}
);
let content =
"Little princeAntoine de Saint-Exupéry";
convert_and_validate!(
content,
Book,
Book {
author: "Antoine de Saint-Exupéry".to_owned(),
title: "Little prince".to_owned(),
}
);
}
#[test]
fn de_multiple_segments() {
init();
mod other_mod {
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct Page {
pub number: i32,
pub text: String,
}
}
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
author: String,
title: String,
page: other_mod::Page,
}
let content = r#"
Antoine de Saint-Exupéry
Little prince
40
The Earth is not just an ordinary planet!
"#;
convert_and_validate!(
content,
Book,
Book {
author: "Antoine de Saint-Exupéry".to_owned(),
title: "Little prince".to_owned(),
page: other_mod::Page {
number: 40,
text: "The Earth is not just an ordinary planet!".to_owned(),
},
}
);
}
#[test]
fn de_list_of_items() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "library")]
pub struct Library {
books: Vec,
}
let content = "Little PrinceHarry Potter";
convert_and_validate!(
content,
Library,
Library {
books: vec!["Little Prince".to_owned(), "Harry Potter".to_owned()],
}
);
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "libraries")]
pub struct Libraries {
library: Vec,
}
let content = "Little PrinceHarry Potter";
convert_and_validate!(
content,
Libraries,
Libraries {
library: vec![
Library {
books: vec!["Little Prince".to_owned()],
},
Library {
books: vec!["Harry Potter".to_owned()],
},
],
}
);
}
#[test]
fn de_attributes() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
#[yaserde(attribute = true)]
item: String,
sub: SubStruct,
}
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "sub")]
pub struct SubStruct {
#[yaserde(attribute = true)]
subitem: String,
}
let content = "";
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
item: "something".to_string(),
sub: SubStruct {
subitem: "sub-something".to_string(),
},
}
);
}
#[test]
fn de_attributes_custom_deserializer() {
init();
mod other_mod {
use super::*;
use xml::reader::XmlEvent;
#[derive(Debug, PartialEq)]
pub struct Attributes {
pub items: Vec,
}
impl YaDeserialize for Attributes {
fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result {
loop {
match reader.next_event()? {
XmlEvent::StartElement { .. } => {}
XmlEvent::Characters(ref text_content) => {
let items: Vec = text_content
.split(' ')
.map(|item| item.to_owned())
.collect();
return Ok(Attributes { items });
}
_ => {
break;
}
}
}
Err("Unable to parse attribute".to_string())
}
}
}
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct Struct {
#[yaserde(attribute = true)]
attr_option_string: Option,
#[yaserde(attribute = true)]
attr_option_struct: Option,
}
convert_and_validate!(
r#""#,
Struct,
Struct {
attr_option_string: None,
attr_option_struct: None
}
);
convert_and_validate!(
r#""#,
Struct,
Struct {
attr_option_string: Some("some value".to_string()),
attr_option_struct: Some(other_mod::Attributes {
items: vec!["variant2".to_string(), "variant3".to_string()]
})
}
);
}
#[test]
fn de_attributes_complex() {
init();
mod other_mod {
#[derive(Default, YaDeserialize, PartialEq, Debug)]
pub enum AttrEnum {
#[default]
#[yaserde(rename = "variant 1")]
Variant1,
#[yaserde(rename = "variant 2")]
Variant2,
}
}
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct Struct {
#[yaserde(attribute = true)]
attr_option_string: Option,
#[yaserde(attribute = true)]
attr_option_enum: Option,
}
convert_and_validate!(
r#""#,
Struct,
Struct {
attr_option_string: None,
attr_option_enum: None
}
);
convert_and_validate!(
r#""#,
Struct,
Struct {
attr_option_string: Some("some value".to_string()),
attr_option_enum: Some(other_mod::AttrEnum::Variant2)
}
);
}
#[test]
fn de_attributes_with_same_name_field() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct Struct {
#[yaserde(attribute = true, rename = "content")]
attribute: Option,
content: Option,
}
convert_and_validate!(
r#""#,
Struct,
Struct {
attribute: None,
content: None
}
);
convert_and_validate!(
r#""#,
Struct,
Struct {
attribute: Some("attribute".to_string()),
content: None
}
);
convert_and_validate!(
r#"Field"#,
Struct,
Struct {
attribute: Some("attribute".to_string()),
content: Some("Field".to_string())
}
);
}
#[test]
fn de_rename() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
#[yaserde(attribute = true, rename = "Item")]
item: String,
#[yaserde(rename = "sub")]
sub_struct: SubStruct,
#[yaserde(rename = "maj.min.bug")]
with_dots: String,
}
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "sub")]
pub struct SubStruct {
#[yaserde(attribute = true, rename = "sub_item")]
subitem: String,
}
let content = "2.0.1";
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
item: "something".to_string(),
sub_struct: SubStruct {
subitem: "sub_something".to_string(),
},
with_dots: "2.0.1".into()
}
);
}
#[test]
fn de_text_content_with_attributes() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
#[yaserde(attribute = true, rename = "Item")]
item: String,
#[yaserde(rename = "sub")]
sub_struct: SubStruct,
}
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "sub")]
pub struct SubStruct {
#[yaserde(attribute = true, rename = "sub_item")]
subitem: String,
#[yaserde(text = true)]
text: String,
}
let content =
"text_content";
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
item: "something".to_string(),
sub_struct: SubStruct {
subitem: "sub_something".to_string(),
text: "text_content".to_string(),
},
}
);
}
#[test]
fn de_text_attribute_on_optional_string() {
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
#[yaserde(text = true)]
text: Option,
}
let model = XmlStruct {
text: Some("Testing text".to_string()),
};
let content = r#"Testing text"#;
convert_and_validate!(content, XmlStruct, model);
let model = XmlStruct { text: None };
let content = r#""#;
convert_and_validate!(content, XmlStruct, model);
}
#[test]
fn de_enum() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
background: Color,
}
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct Colors {
items: Vec,
}
#[derive(Default, YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "color")]
pub enum Color {
#[default]
White,
Black,
}
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct RGBColor {
red: String,
green: String,
blue: String,
}
let content =
"Black";
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Black,
}
);
let content = "BlackWhite";
convert_and_validate!(
content,
Colors,
Colors {
items: vec![Color::Black, Color::White],
}
);
}
#[test]
fn de_attribute_enum() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "base")]
pub struct XmlStruct {
#[yaserde(attribute = true)]
background: Color,
}
#[derive(Default, YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "color")]
pub enum Color {
#[default]
White,
Black,
}
let content = "";
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Black,
}
);
}
#[test]
fn de_complex_enum() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct XmlStruct {
background: Color,
}
#[derive(YaDeserialize, PartialEq, Debug)]
pub struct OtherStruct {
fi: i32,
se: i32,
}
#[derive(Default, YaDeserialize, PartialEq, Debug)]
pub enum Color {
#[default]
White,
Black(String),
Orange(String),
Red(i32),
Green(OtherStruct),
Yellow(Option),
Brown(Option),
Blue(Vec),
Purple(Vec),
Magenta(Vec),
#[yaserde(rename = "NotSoCyan")]
Cyan(Vec),
#[yaserde(rename = "renamed.with.dots")]
Dotted(u32),
}
let content = r#"
text
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Black("text".to_owned()),
}
);
let content = r#"
text
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Orange("text".to_owned()),
}
);
let content = r#"
56
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Red(56),
}
);
let content = r#"
12
23
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Green(OtherStruct { fi: 12, se: 23 }),
}
);
let content = r#"
text
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Yellow(Some("text".to_owned())),
}
);
let content = r#"
12
23
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Brown(Some(OtherStruct { fi: 12, se: 23 })),
}
);
let content = r#"
abc
def
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Blue(vec!["abc".to_owned(), "def".to_owned()]),
}
);
let content = r#"
12
43
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Purple(vec![12, 43]),
}
);
let content = r#"
1223
6398
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Magenta(vec![
OtherStruct { fi: 12, se: 23 },
OtherStruct { fi: 63, se: 98 }
]),
}
);
let content = r#"
1223
6398
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Cyan(vec![
OtherStruct { fi: 12, se: 23 },
OtherStruct { fi: 63, se: 98 }
])
}
);
let content = r#"
54
"#;
convert_and_validate!(
content,
XmlStruct,
XmlStruct {
background: Color::Dotted(54)
}
);
}
#[test]
fn de_name_issue_21() {
init();
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(rename = "book")]
pub struct Book {
name: String,
}
let content = "Little prince";
convert_and_validate!(
content,
Book,
Book {
name: "Little prince".to_owned(),
}
);
}
#[test]
fn de_custom() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
struct Date {
#[yaserde(rename = "Year")]
year: i32,
#[yaserde(rename = "Month")]
month: i32,
#[yaserde(rename = "Day")]
day: Day,
}
#[derive(PartialEq, Debug)]
struct Day {
value: i32,
}
impl YaDeserialize for Day {
fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result {
use std::str::FromStr;
if let xml::reader::XmlEvent::StartElement { name, .. } = reader.peek()?.to_owned() {
let expected_name = "Day".to_owned();
if name.local_name != expected_name {
return Err(format!(
"Wrong StartElement name: {}, expected: {}",
name, expected_name
));
}
let _next = reader.next_event();
} else {
return Err("StartElement missing".to_string());
}
if let xml::reader::XmlEvent::Characters(text) = reader.peek()?.to_owned() {
Ok(Day {
value: 2 * i32::from_str(&text).unwrap(),
})
} else {
Err("Characters missing".to_string())
}
}
}
let content = "20200111";
let model: Date = from_str(content).unwrap();
assert_eq!(
model,
Date {
year: 2020,
month: 1,
day: Day { value: 11 * 2 }
}
);
}
#[test]
fn de_subitem_issue_12() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
id: i32,
}
convert_and_validate!(
r#"
54
86
"#,
Struct,
Struct { id: 54 }
);
}
#[test]
fn de_subitem_issue_12_with_sub() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct SubStruct {
id: i32,
}
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
id: i32,
#[yaserde(rename = "SubStruct")]
sub: SubStruct,
}
convert_and_validate!(
r#"
54
86
"#,
Struct,
Struct {
id: 54,
sub: SubStruct { id: 86 }
}
);
}
#[test]
fn de_subitem_issue_12_attributes() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
#[yaserde(attribute = true)]
id: i32,
}
convert_and_validate!(
r#"
"#,
Struct,
Struct { id: 54 }
);
}
#[test]
fn de_subitem_issue_12_attributes_with_sub() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct SubStruct {
#[yaserde(attribute = true)]
id: i32,
}
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
#[yaserde(attribute = true)]
id: i32,
sub1: SubStruct,
sub2: SubStruct,
}
convert_and_validate!(
r#"
"#,
Struct,
Struct {
id: 54,
sub1: SubStruct { id: 63 },
sub2: SubStruct { id: 72 }
}
);
}
#[test]
fn de_same_field_name_sub() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct SubStruct {
sub: Option,
}
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
sub: SubStruct,
}
convert_and_validate!(
"",
Struct,
Struct {
sub: SubStruct { sub: None }
}
);
convert_and_validate!(
"42",
Struct,
Struct {
sub: SubStruct { sub: Some(42) }
}
);
}
#[test]
fn de_same_field_name_sub_sub() {
init();
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct SubSubStruct {
sub: i32,
}
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct SubStruct {
sub: Option,
}
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Struct {
sub: SubStruct,
}
convert_and_validate!(
"",
Struct,
Struct {
sub: SubStruct { sub: None }
}
);
convert_and_validate!(
"
42
",
Struct,
Struct {
sub: SubStruct {
sub: Some(SubSubStruct { sub: 42 })
}
}
);
}
#[test]
fn de_same_field_name_but_some_other_fields_or_something() {
init();
#[derive(PartialEq, Debug, YaDeserialize, YaSerialize)]
#[yaserde(rename = "foo")]
pub struct FooOuter {
pub other: bool,
#[yaserde(rename = "foo")]
pub foo: Option,
}
#[derive(PartialEq, Debug, YaDeserialize, YaSerialize)]
pub struct FooInner {
pub blah: bool,
}
let content = r#"
false
false
"#;
let model = FooOuter {
other: false,
foo: Some(FooInner { blah: false }),
};
serialize_and_validate!(model, content);
deserialize_and_validate!(content, model, FooOuter);
}
#[test]
fn de_attribute_sequence() {
init();
#[derive(Default, Debug, YaDeserialize, PartialEq)]
pub enum Inner {
#[default]
#[yaserde(rename = "foo")]
Foo,
#[yaserde(rename = "bar")]
Bar,
}
#[derive(Debug, PartialEq, YaDeserialize)]
pub struct Outer {
#[yaserde(attribute = true, rename = "seq1")]
seq1: Vec,
#[yaserde(attribute = true, rename = "seq2")]
seq2: Vec,
#[yaserde(attribute = true, rename = "seq3")]
seq3: Vec,
}
let content = r#""#;
let model = Outer {
seq1: vec![1, 2, 3, 4],
seq2: vec![Inner::Foo, Inner::Foo, Inner::Bar],
seq3: vec!["one".to_string(), "two".to_string()],
};
//serialize_and_validate!(model, content);
deserialize_and_validate!(content, model, Outer);
}
#[test]
fn de_nested_macro_rules() {
init();
macro_rules! float_attrs {
($type:ty) => {
#[derive(PartialEq, Debug, YaDeserialize)]
pub struct Outer {
#[yaserde(attribute = true)]
pub inner: Option<$type>,
}
};
}
float_attrs!(f32);
}