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