1 #![allow(
2 clippy::cast_lossless,
3 clippy::cast_possible_wrap,
4 clippy::derive_partial_eq_without_eq,
5 clippy::similar_names,
6 clippy::uninlined_format_args
7 )]
8
9 use indoc::indoc;
10 use serde_derive::Deserialize;
11 use serde_yaml::{Deserializer, Number, Value};
12 use std::collections::BTreeMap;
13 use std::fmt::Debug;
14
test_de<T>(yaml: &str, expected: &T) where T: serde::de::DeserializeOwned + PartialEq + Debug,15 fn test_de<T>(yaml: &str, expected: &T)
16 where
17 T: serde::de::DeserializeOwned + PartialEq + Debug,
18 {
19 let deserialized: T = serde_yaml::from_str(yaml).unwrap();
20 assert_eq!(*expected, deserialized);
21
22 let value: Value = serde_yaml::from_str(yaml).unwrap();
23 let deserialized = T::deserialize(&value).unwrap();
24 assert_eq!(*expected, deserialized);
25
26 let deserialized: T = serde_yaml::from_value(value).unwrap();
27 assert_eq!(*expected, deserialized);
28
29 serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
30
31 let mut deserializer = Deserializer::from_str(yaml);
32 let document = deserializer.next().unwrap();
33 let deserialized = T::deserialize(document).unwrap();
34 assert_eq!(*expected, deserialized);
35 assert!(deserializer.next().is_none());
36 }
37
test_de_no_value<'de, T>(yaml: &'de str, expected: &T) where T: serde::de::Deserialize<'de> + PartialEq + Debug,38 fn test_de_no_value<'de, T>(yaml: &'de str, expected: &T)
39 where
40 T: serde::de::Deserialize<'de> + PartialEq + Debug,
41 {
42 let deserialized: T = serde_yaml::from_str(yaml).unwrap();
43 assert_eq!(*expected, deserialized);
44
45 serde_yaml::from_str::<serde_yaml::Value>(yaml).unwrap();
46 serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
47 }
48
test_de_seed<'de, T, S>(yaml: &'de str, seed: S, expected: &T) where T: PartialEq + Debug, S: serde::de::DeserializeSeed<'de, Value = T>,49 fn test_de_seed<'de, T, S>(yaml: &'de str, seed: S, expected: &T)
50 where
51 T: PartialEq + Debug,
52 S: serde::de::DeserializeSeed<'de, Value = T>,
53 {
54 let deserialized: T = seed.deserialize(Deserializer::from_str(yaml)).unwrap();
55 assert_eq!(*expected, deserialized);
56
57 serde_yaml::from_str::<serde_yaml::Value>(yaml).unwrap();
58 serde_yaml::from_str::<serde::de::IgnoredAny>(yaml).unwrap();
59 }
60
61 #[test]
test_borrowed()62 fn test_borrowed() {
63 let yaml = indoc! {"
64 - plain nonàscii
65 - 'single quoted'
66 - \"double quoted\"
67 "};
68 let expected = vec!["plain nonàscii", "single quoted", "double quoted"];
69 test_de_no_value(yaml, &expected);
70 }
71
72 #[test]
test_alias()73 fn test_alias() {
74 let yaml = indoc! {"
75 first:
76 &alias
77 1
78 second:
79 *alias
80 third: 3
81 "};
82 let mut expected = BTreeMap::new();
83 expected.insert("first".to_owned(), 1);
84 expected.insert("second".to_owned(), 1);
85 expected.insert("third".to_owned(), 3);
86 test_de(yaml, &expected);
87 }
88
89 #[test]
test_option()90 fn test_option() {
91 #[derive(Deserialize, PartialEq, Debug)]
92 struct Data {
93 a: Option<f64>,
94 b: Option<String>,
95 c: Option<bool>,
96 }
97 let yaml = indoc! {"
98 b:
99 c: true
100 "};
101 let expected = Data {
102 a: None,
103 b: None,
104 c: Some(true),
105 };
106 test_de(yaml, &expected);
107 }
108
109 #[test]
test_option_alias()110 fn test_option_alias() {
111 #[derive(Deserialize, PartialEq, Debug)]
112 struct Data {
113 a: Option<f64>,
114 b: Option<String>,
115 c: Option<bool>,
116 d: Option<f64>,
117 e: Option<String>,
118 f: Option<bool>,
119 }
120 let yaml = indoc! {"
121 none_f:
122 &none_f
123 ~
124 none_s:
125 &none_s
126 ~
127 none_b:
128 &none_b
129 ~
130
131 some_f:
132 &some_f
133 1.0
134 some_s:
135 &some_s
136 x
137 some_b:
138 &some_b
139 true
140
141 a: *none_f
142 b: *none_s
143 c: *none_b
144 d: *some_f
145 e: *some_s
146 f: *some_b
147 "};
148 let expected = Data {
149 a: None,
150 b: None,
151 c: None,
152 d: Some(1.0),
153 e: Some("x".to_owned()),
154 f: Some(true),
155 };
156 test_de(yaml, &expected);
157 }
158
159 #[test]
test_enum_alias()160 fn test_enum_alias() {
161 #[derive(Deserialize, PartialEq, Debug)]
162 enum E {
163 A,
164 B(u8, u8),
165 }
166 #[derive(Deserialize, PartialEq, Debug)]
167 struct Data {
168 a: E,
169 b: E,
170 }
171 let yaml = indoc! {"
172 aref:
173 &aref
174 A
175 bref:
176 &bref
177 !B
178 - 1
179 - 2
180
181 a: *aref
182 b: *bref
183 "};
184 let expected = Data {
185 a: E::A,
186 b: E::B(1, 2),
187 };
188 test_de(yaml, &expected);
189 }
190
191 #[test]
test_enum_representations()192 fn test_enum_representations() {
193 #[derive(Deserialize, PartialEq, Debug)]
194 enum Enum {
195 Unit,
196 Tuple(i32, i32),
197 Struct { x: i32, y: i32 },
198 String(String),
199 Number(f64),
200 }
201
202 let yaml = indoc! {"
203 - Unit
204 - 'Unit'
205 - !Unit
206 - !Unit ~
207 - !Unit null
208 - !Tuple [0, 0]
209 - !Tuple
210 - 0
211 - 0
212 - !Struct {x: 0, y: 0}
213 - !Struct
214 x: 0
215 y: 0
216 - !String '...'
217 - !String ...
218 - !Number 0
219 "};
220
221 let expected = vec![
222 Enum::Unit,
223 Enum::Unit,
224 Enum::Unit,
225 Enum::Unit,
226 Enum::Unit,
227 Enum::Tuple(0, 0),
228 Enum::Tuple(0, 0),
229 Enum::Struct { x: 0, y: 0 },
230 Enum::Struct { x: 0, y: 0 },
231 Enum::String("...".to_owned()),
232 Enum::String("...".to_owned()),
233 Enum::Number(0.0),
234 ];
235
236 test_de(yaml, &expected);
237
238 let yaml = indoc! {"
239 - !String
240 "};
241 let expected = vec![Enum::String(String::new())];
242 test_de_no_value(yaml, &expected);
243 }
244
245 #[test]
test_number_as_string()246 fn test_number_as_string() {
247 #[derive(Deserialize, PartialEq, Debug)]
248 struct Num {
249 value: String,
250 }
251 let yaml = indoc! {"
252 # Cannot be represented as u128
253 value: 340282366920938463463374607431768211457
254 "};
255 let expected = Num {
256 value: "340282366920938463463374607431768211457".to_owned(),
257 };
258 test_de_no_value(yaml, &expected);
259 }
260
261 #[test]
test_empty_string()262 fn test_empty_string() {
263 #[derive(Deserialize, PartialEq, Debug)]
264 struct Struct {
265 empty: String,
266 tilde: String,
267 }
268 let yaml = indoc! {"
269 empty:
270 tilde: ~
271 "};
272 let expected = Struct {
273 empty: String::new(),
274 tilde: "~".to_owned(),
275 };
276 test_de_no_value(yaml, &expected);
277 }
278
279 #[test]
test_i128_big()280 fn test_i128_big() {
281 let expected: i128 = i64::MIN as i128 - 1;
282 let yaml = indoc! {"
283 -9223372036854775809
284 "};
285 assert_eq!(expected, serde_yaml::from_str::<i128>(yaml).unwrap());
286
287 let octal = indoc! {"
288 -0o1000000000000000000001
289 "};
290 assert_eq!(expected, serde_yaml::from_str::<i128>(octal).unwrap());
291 }
292
293 #[test]
test_u128_big()294 fn test_u128_big() {
295 let expected: u128 = u64::MAX as u128 + 1;
296 let yaml = indoc! {"
297 18446744073709551616
298 "};
299 assert_eq!(expected, serde_yaml::from_str::<u128>(yaml).unwrap());
300
301 let octal = indoc! {"
302 0o2000000000000000000000
303 "};
304 assert_eq!(expected, serde_yaml::from_str::<u128>(octal).unwrap());
305 }
306
307 #[test]
test_number_alias_as_string()308 fn test_number_alias_as_string() {
309 #[derive(Deserialize, PartialEq, Debug)]
310 struct Num {
311 version: String,
312 value: String,
313 }
314 let yaml = indoc! {"
315 version: &a 1.10
316 value: *a
317 "};
318 let expected = Num {
319 version: "1.10".to_owned(),
320 value: "1.10".to_owned(),
321 };
322 test_de_no_value(yaml, &expected);
323 }
324
325 #[test]
test_de_mapping()326 fn test_de_mapping() {
327 #[derive(Debug, Deserialize, PartialEq)]
328 struct Data {
329 pub substructure: serde_yaml::Mapping,
330 }
331 let yaml = indoc! {"
332 substructure:
333 a: 'foo'
334 b: 'bar'
335 "};
336
337 let mut expected = Data {
338 substructure: serde_yaml::Mapping::new(),
339 };
340 expected.substructure.insert(
341 serde_yaml::Value::String("a".to_owned()),
342 serde_yaml::Value::String("foo".to_owned()),
343 );
344 expected.substructure.insert(
345 serde_yaml::Value::String("b".to_owned()),
346 serde_yaml::Value::String("bar".to_owned()),
347 );
348
349 test_de(yaml, &expected);
350 }
351
352 #[test]
test_byte_order_mark()353 fn test_byte_order_mark() {
354 let yaml = "\u{feff}- 0\n";
355 let expected = vec![0];
356 test_de(yaml, &expected);
357 }
358
359 #[test]
test_bomb()360 fn test_bomb() {
361 #[derive(Debug, Deserialize, PartialEq)]
362 struct Data {
363 expected: String,
364 }
365
366 // This would deserialize an astronomical number of elements if we were
367 // vulnerable.
368 let yaml = indoc! {"
369 a: &a ~
370 b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
371 c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
372 d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
373 e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
374 f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
375 g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
376 h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
377 i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
378 j: &j [*i,*i,*i,*i,*i,*i,*i,*i,*i]
379 k: &k [*j,*j,*j,*j,*j,*j,*j,*j,*j]
380 l: &l [*k,*k,*k,*k,*k,*k,*k,*k,*k]
381 m: &m [*l,*l,*l,*l,*l,*l,*l,*l,*l]
382 n: &n [*m,*m,*m,*m,*m,*m,*m,*m,*m]
383 o: &o [*n,*n,*n,*n,*n,*n,*n,*n,*n]
384 p: &p [*o,*o,*o,*o,*o,*o,*o,*o,*o]
385 q: &q [*p,*p,*p,*p,*p,*p,*p,*p,*p]
386 r: &r [*q,*q,*q,*q,*q,*q,*q,*q,*q]
387 s: &s [*r,*r,*r,*r,*r,*r,*r,*r,*r]
388 t: &t [*s,*s,*s,*s,*s,*s,*s,*s,*s]
389 u: &u [*t,*t,*t,*t,*t,*t,*t,*t,*t]
390 v: &v [*u,*u,*u,*u,*u,*u,*u,*u,*u]
391 w: &w [*v,*v,*v,*v,*v,*v,*v,*v,*v]
392 x: &x [*w,*w,*w,*w,*w,*w,*w,*w,*w]
393 y: &y [*x,*x,*x,*x,*x,*x,*x,*x,*x]
394 z: &z [*y,*y,*y,*y,*y,*y,*y,*y,*y]
395 expected: string
396 "};
397
398 let expected = Data {
399 expected: "string".to_owned(),
400 };
401
402 assert_eq!(expected, serde_yaml::from_str::<Data>(yaml).unwrap());
403 }
404
405 #[test]
test_numbers()406 fn test_numbers() {
407 let cases = [
408 ("0xF0", "240"),
409 ("+0xF0", "240"),
410 ("-0xF0", "-240"),
411 ("0o70", "56"),
412 ("+0o70", "56"),
413 ("-0o70", "-56"),
414 ("0b10", "2"),
415 ("+0b10", "2"),
416 ("-0b10", "-2"),
417 ("127", "127"),
418 ("+127", "127"),
419 ("-127", "-127"),
420 (".inf", ".inf"),
421 (".Inf", ".inf"),
422 (".INF", ".inf"),
423 ("-.inf", "-.inf"),
424 ("-.Inf", "-.inf"),
425 ("-.INF", "-.inf"),
426 (".nan", ".nan"),
427 (".NaN", ".nan"),
428 (".NAN", ".nan"),
429 ("0.1", "0.1"),
430 ];
431 for &(yaml, expected) in &cases {
432 let value = serde_yaml::from_str::<Value>(yaml).unwrap();
433 match value {
434 Value::Number(number) => assert_eq!(number.to_string(), expected),
435 _ => panic!("expected number. input={:?}, result={:?}", yaml, value),
436 }
437 }
438
439 // NOT numbers.
440 let cases = [
441 "0127", "+0127", "-0127", "++.inf", "+-.inf", "++1", "+-1", "-+1", "--1", "0x+1", "0x-1",
442 "-0x+1", "-0x-1", "++0x1", "+-0x1", "-+0x1", "--0x1",
443 ];
444 for yaml in &cases {
445 let value = serde_yaml::from_str::<Value>(yaml).unwrap();
446 match value {
447 Value::String(string) => assert_eq!(string, *yaml),
448 _ => panic!("expected string. input={:?}, result={:?}", yaml, value),
449 }
450 }
451 }
452
453 #[test]
test_nan()454 fn test_nan() {
455 // There is no negative NaN in YAML.
456 assert!(serde_yaml::from_str::<f32>(".nan")
457 .unwrap()
458 .is_sign_positive());
459 assert!(serde_yaml::from_str::<f64>(".nan")
460 .unwrap()
461 .is_sign_positive());
462 }
463
464 #[test]
test_stateful()465 fn test_stateful() {
466 struct Seed(i64);
467
468 impl<'de> serde::de::DeserializeSeed<'de> for Seed {
469 type Value = i64;
470 fn deserialize<D>(self, deserializer: D) -> Result<i64, D::Error>
471 where
472 D: serde::de::Deserializer<'de>,
473 {
474 struct Visitor(i64);
475 impl<'de> serde::de::Visitor<'de> for Visitor {
476 type Value = i64;
477
478 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
479 write!(formatter, "an integer")
480 }
481
482 fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<i64, E> {
483 Ok(v * self.0)
484 }
485
486 fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<i64, E> {
487 Ok(v as i64 * self.0)
488 }
489 }
490
491 deserializer.deserialize_any(Visitor(self.0))
492 }
493 }
494
495 let cases = [("3", 5, 15), ("6", 7, 42), ("-5", 9, -45)];
496 for &(yaml, seed, expected) in &cases {
497 test_de_seed(yaml, Seed(seed), &expected);
498 }
499 }
500
501 #[test]
test_ignore_tag()502 fn test_ignore_tag() {
503 #[derive(Deserialize, Debug, PartialEq)]
504 struct Data {
505 struc: Struc,
506 tuple: Tuple,
507 newtype: Newtype,
508 map: BTreeMap<char, usize>,
509 vec: Vec<usize>,
510 }
511
512 #[derive(Deserialize, Debug, PartialEq)]
513 struct Struc {
514 x: usize,
515 }
516
517 #[derive(Deserialize, Debug, PartialEq)]
518 struct Tuple(usize, usize);
519
520 #[derive(Deserialize, Debug, PartialEq)]
521 struct Newtype(usize);
522
523 let yaml = indoc! {"
524 struc: !wat
525 x: 0
526 tuple: !wat
527 - 0
528 - 0
529 newtype: !wat 0
530 map: !wat
531 x: 0
532 vec: !wat
533 - 0
534 "};
535
536 let expected = Data {
537 struc: Struc { x: 0 },
538 tuple: Tuple(0, 0),
539 newtype: Newtype(0),
540 map: {
541 let mut map = BTreeMap::new();
542 map.insert('x', 0);
543 map
544 },
545 vec: vec![0],
546 };
547
548 test_de(yaml, &expected);
549 }
550
551 #[test]
test_no_required_fields()552 fn test_no_required_fields() {
553 #[derive(Deserialize, PartialEq, Debug)]
554 pub struct NoRequiredFields {
555 optional: Option<usize>,
556 }
557
558 for document in ["", "# comment\n"] {
559 let expected = NoRequiredFields { optional: None };
560 let deserialized: NoRequiredFields = serde_yaml::from_str(document).unwrap();
561 assert_eq!(expected, deserialized);
562
563 let expected = Vec::<String>::new();
564 let deserialized: Vec<String> = serde_yaml::from_str(document).unwrap();
565 assert_eq!(expected, deserialized);
566
567 let expected = BTreeMap::new();
568 let deserialized: BTreeMap<char, usize> = serde_yaml::from_str(document).unwrap();
569 assert_eq!(expected, deserialized);
570
571 let expected = None;
572 let deserialized: Option<String> = serde_yaml::from_str(document).unwrap();
573 assert_eq!(expected, deserialized);
574
575 let expected = Value::Null;
576 let deserialized: Value = serde_yaml::from_str(document).unwrap();
577 assert_eq!(expected, deserialized);
578 }
579 }
580
581 #[test]
test_empty_scalar()582 fn test_empty_scalar() {
583 #[derive(Deserialize, PartialEq, Debug)]
584 struct Struct<T> {
585 thing: T,
586 }
587
588 let yaml = "thing:\n";
589 let expected = Struct {
590 thing: serde_yaml::Sequence::new(),
591 };
592 test_de(yaml, &expected);
593
594 let expected = Struct {
595 thing: serde_yaml::Mapping::new(),
596 };
597 test_de(yaml, &expected);
598 }
599
600 #[test]
test_python_safe_dump()601 fn test_python_safe_dump() {
602 #[derive(Deserialize, PartialEq, Debug)]
603 struct Frob {
604 foo: u32,
605 }
606
607 // This matches output produced by PyYAML's `yaml.safe_dump` when using the
608 // default_style parameter.
609 //
610 // >>> import yaml
611 // >>> d = {"foo": 7200}
612 // >>> print(yaml.safe_dump(d, default_style="|"))
613 // "foo": !!int |-
614 // 7200
615 //
616 let yaml = indoc! {r#"
617 "foo": !!int |-
618 7200
619 "#};
620
621 let expected = Frob { foo: 7200 };
622 test_de(yaml, &expected);
623 }
624
625 #[test]
test_tag_resolution()626 fn test_tag_resolution() {
627 // https://yaml.org/spec/1.2.2/#1032-tag-resolution
628 let yaml = indoc! {"
629 - null
630 - Null
631 - NULL
632 - ~
633 -
634 - true
635 - True
636 - TRUE
637 - false
638 - False
639 - FALSE
640 - y
641 - Y
642 - yes
643 - Yes
644 - YES
645 - n
646 - N
647 - no
648 - No
649 - NO
650 - on
651 - On
652 - ON
653 - off
654 - Off
655 - OFF
656 "};
657
658 let expected = vec![
659 Value::Null,
660 Value::Null,
661 Value::Null,
662 Value::Null,
663 Value::Null,
664 Value::Bool(true),
665 Value::Bool(true),
666 Value::Bool(true),
667 Value::Bool(false),
668 Value::Bool(false),
669 Value::Bool(false),
670 Value::String("y".to_owned()),
671 Value::String("Y".to_owned()),
672 Value::String("yes".to_owned()),
673 Value::String("Yes".to_owned()),
674 Value::String("YES".to_owned()),
675 Value::String("n".to_owned()),
676 Value::String("N".to_owned()),
677 Value::String("no".to_owned()),
678 Value::String("No".to_owned()),
679 Value::String("NO".to_owned()),
680 Value::String("on".to_owned()),
681 Value::String("On".to_owned()),
682 Value::String("ON".to_owned()),
683 Value::String("off".to_owned()),
684 Value::String("Off".to_owned()),
685 Value::String("OFF".to_owned()),
686 ];
687
688 test_de(yaml, &expected);
689 }
690
691 #[test]
test_parse_number()692 fn test_parse_number() {
693 let n = "111".parse::<Number>().unwrap();
694 assert_eq!(n, Number::from(111));
695
696 let n = "-111".parse::<Number>().unwrap();
697 assert_eq!(n, Number::from(-111));
698
699 let n = "-1.1".parse::<Number>().unwrap();
700 assert_eq!(n, Number::from(-1.1));
701
702 let n = ".nan".parse::<Number>().unwrap();
703 assert_eq!(n, Number::from(f64::NAN));
704 assert!(n.as_f64().unwrap().is_sign_positive());
705
706 let n = ".inf".parse::<Number>().unwrap();
707 assert_eq!(n, Number::from(f64::INFINITY));
708
709 let n = "-.inf".parse::<Number>().unwrap();
710 assert_eq!(n, Number::from(f64::NEG_INFINITY));
711
712 let err = "null".parse::<Number>().unwrap_err();
713 assert_eq!(err.to_string(), "failed to parse YAML number");
714
715 let err = " 1 ".parse::<Number>().unwrap_err();
716 assert_eq!(err.to_string(), "failed to parse YAML number");
717 }
718