1#![warn(missing_docs)]
111#![warn(rust_2018_idioms)]
112#![deny(unsafe_op_in_unsafe_fn)]
113
114pub mod de;
115pub mod error;
116pub mod escape;
117pub mod reader;
118pub mod ser;
119pub mod writer;
120
121pub use de::{from_bytes, from_str, Deserializer};
123pub use error::{Error, ErrorKind, Position, Result};
124pub use escape::{escape, unescape};
125pub use reader::{Attribute, XmlEvent, XmlReader};
126pub use ser::{to_string, to_string_with_root, to_vec, to_writer, Serializer};
127pub use writer::{IndentConfig, XmlWriter};
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132 use serde::{Deserialize, Serialize};
133
134 #[test]
135 fn test_roundtrip_simple() {
136 #[derive(Debug, Serialize, Deserialize, PartialEq)]
137 struct Person {
138 name: String,
139 age: u32,
140 }
141
142 let original = Person {
143 name: "Alice".to_string(),
144 age: 30,
145 };
146
147 let xml = to_string(&original).unwrap();
148 let parsed: Person = from_str(&xml).unwrap();
149 assert_eq!(original, parsed);
150 }
151
152 #[test]
153 fn test_roundtrip_nested() {
154 #[derive(Debug, Serialize, Deserialize, PartialEq)]
155 struct Address {
156 city: String,
157 country: String,
158 }
159
160 #[derive(Debug, Serialize, Deserialize, PartialEq)]
161 struct Person {
162 name: String,
163 address: Address,
164 }
165
166 let original = Person {
167 name: "Bob".to_string(),
168 address: Address {
169 city: "New York".to_string(),
170 country: "USA".to_string(),
171 },
172 };
173
174 let xml = to_string(&original).unwrap();
175 let parsed: Person = from_str(&xml).unwrap();
176 assert_eq!(original, parsed);
177 }
178
179 #[test]
180 fn test_roundtrip_vector() {
181 #[derive(Debug, Serialize, Deserialize, PartialEq)]
182 struct Items {
183 item: Vec<String>,
184 }
185
186 let original = Items {
187 item: vec!["one".to_string(), "two".to_string(), "three".to_string()],
188 };
189
190 let xml = to_string(&original).unwrap();
191 let parsed: Items = from_str(&xml).unwrap();
192 assert_eq!(original, parsed);
193 }
194
195 #[test]
196 fn test_roundtrip_optional() {
197 #[derive(Debug, Serialize, Deserialize, PartialEq)]
198 struct Config {
199 name: String,
200 value: Option<String>,
201 }
202
203 let with_value = Config {
204 name: "test".to_string(),
205 value: Some("val".to_string()),
206 };
207
208 let xml = to_string(&with_value).unwrap();
209 let parsed: Config = from_str(&xml).unwrap();
210 assert_eq!(with_value, parsed);
211 }
212
213 #[test]
214 fn test_roundtrip_escaped() {
215 #[derive(Debug, Serialize, Deserialize, PartialEq)]
216 struct Data {
217 content: String,
218 }
219
220 let original = Data {
221 content: "<hello> & \"world\"".to_string(),
222 };
223
224 let xml = to_string(&original).unwrap();
225 let parsed: Data = from_str(&xml).unwrap();
226 assert_eq!(original, parsed);
227 }
228
229 #[test]
230 fn test_xml_reader_basic() {
231 let mut reader = XmlReader::from_str("<root><child>text</child></root>");
232
233 match reader.next_event().unwrap() {
234 XmlEvent::StartElement { name, .. } => assert_eq!(name, "root"),
235 _ => panic!("expected StartElement"),
236 }
237
238 match reader.next_event().unwrap() {
239 XmlEvent::StartElement { name, .. } => assert_eq!(name, "child"),
240 _ => panic!("expected StartElement"),
241 }
242
243 match reader.next_event().unwrap() {
244 XmlEvent::Text(text) => assert_eq!(text, "text"),
245 _ => panic!("expected Text"),
246 }
247 }
248
249 #[test]
250 fn test_xml_writer_basic() {
251
252 let mut buffer = Vec::new();
253 {
254 let mut writer = XmlWriter::new(&mut buffer);
255 writer.start_element("root").unwrap();
256 writer.start_element("child").unwrap();
257 writer.write_text("text").unwrap();
258 writer.end_element().unwrap();
259 writer.end_element().unwrap();
260 }
261
262 let xml = String::from_utf8(buffer).unwrap();
263 assert!(xml.contains("<root>"));
264 assert!(xml.contains("<child>text</child>"));
265 }
266
267 #[test]
268 fn test_escape_unescape() {
269 let original = "<hello> & \"world\"";
270 let escaped = escape(original);
271 let unescaped = unescape(&escaped).unwrap();
272 assert_eq!(unescaped, original);
273 }
274
275 #[test]
276 fn test_error_reporting() {
277 #[allow(dead_code)]
279 #[derive(Debug, Deserialize)]
280 struct Item {
281 name: String,
282 }
283
284 let result: Result<Item> = from_str("<Item><name>test</wrong></Item>");
285 assert!(result.is_err());
286 let err = result.unwrap_err();
287 assert!(err.to_string().contains("mismatched") || err.to_string().contains("wrong"));
288 }
289
290 #[test]
291 fn test_complex_xml() {
292 #[derive(Debug, Serialize, Deserialize, PartialEq)]
293 struct Book {
294 title: String,
295 author: String,
296 year: u32,
297 }
298
299 #[derive(Debug, Serialize, Deserialize, PartialEq)]
300 struct Library {
301 name: String,
302 book: Vec<Book>,
303 }
304
305 let original = Library {
306 name: "My Library".to_string(),
307 book: vec![
308 Book {
309 title: "The Rust Programming Language".to_string(),
310 author: "Steve Klabnik".to_string(),
311 year: 2018,
312 },
313 Book {
314 title: "Programming Rust".to_string(),
315 author: "Jim Blandy".to_string(),
316 year: 2021,
317 },
318 ],
319 };
320
321 let xml = to_string(&original).unwrap();
322 let parsed: Library = from_str(&xml).unwrap();
323 assert_eq!(original, parsed);
324 }
325}