blob: 6439bd423552d0974f1856c44c1043d95eb21a48 [file] [log] [blame]
#![allow(clippy::zero_sized_map_values)]
use indoc::indoc;
use serde::de::Deserialize;
#[cfg(not(miri))]
use serde::de::{SeqAccess, Visitor};
use serde_derive::{Deserialize, Serialize};
use serde_yaml::value::{Tag, TaggedValue};
use serde_yaml::{Deserializer, Value};
#[cfg(not(miri))]
use std::collections::BTreeMap;
#[cfg(not(miri))]
use std::fmt;
use std::fmt::Debug;
fn test_error<'de, T>(yaml: &'de str, expected: &str)
where
T: Deserialize<'de> + Debug,
{
let result = serde_yaml::from_str::<T>(yaml);
assert_eq!(expected, result.unwrap_err().to_string());
let mut deserializer = Deserializer::from_str(yaml);
if let Some(first_document) = deserializer.next() {
if deserializer.next().is_none() {
let result = T::deserialize(first_document);
assert_eq!(expected, result.unwrap_err().to_string());
}
}
}
#[test]
fn test_scan_error() {
let yaml = ">\n@";
let expected = "found character that cannot start any token at line 2 column 1, while scanning for the next token";
test_error::<Value>(yaml, expected);
}
#[test]
fn test_incorrect_type() {
let yaml = indoc! {"
---
str
"};
let expected = "invalid type: string \"str\", expected i16 at line 2 column 1";
test_error::<i16>(yaml, expected);
}
#[test]
fn test_incorrect_nested_type() {
#[derive(Deserialize, Debug)]
pub struct A {
pub b: Vec<B>,
}
#[derive(Deserialize, Debug)]
pub enum B {
C(C),
}
#[derive(Deserialize, Debug)]
pub struct C {
pub d: bool,
}
let yaml = indoc! {"
b:
- !C
d: fase
"};
let expected = "b[0].d: invalid type: string \"fase\", expected a boolean at line 3 column 8";
test_error::<A>(yaml, expected);
}
#[test]
fn test_empty() {
let expected = "EOF while parsing a value";
test_error::<String>("", expected);
}
#[test]
fn test_missing_field() {
#[derive(Deserialize, Debug)]
pub struct Basic {
pub v: bool,
pub w: bool,
}
let yaml = indoc! {"
---
v: true
"};
let expected = "missing field `w` at line 2 column 1";
test_error::<Basic>(yaml, expected);
}
#[test]
fn test_unknown_anchor() {
let yaml = indoc! {"
---
*some
"};
let expected = "unknown anchor at line 2 column 1";
test_error::<String>(yaml, expected);
}
#[test]
fn test_ignored_unknown_anchor() {
#[derive(Deserialize, Debug)]
pub struct Wrapper {
pub c: (),
}
let yaml = indoc! {"
b: [*a]
c: ~
"};
let expected = "unknown anchor at line 1 column 5";
test_error::<Wrapper>(yaml, expected);
}
#[test]
fn test_bytes() {
let expected = "serialization and deserialization of bytes in YAML is not implemented";
test_error::<&[u8]>("...", expected);
}
#[test]
fn test_two_documents() {
let yaml = indoc! {"
---
0
---
1
"};
let expected = "deserializing from YAML containing more than one document is not supported";
test_error::<usize>(yaml, expected);
}
#[test]
fn test_second_document_syntax_error() {
let yaml = indoc! {"
---
0
---
]
"};
let mut de = Deserializer::from_str(yaml);
let first_doc = de.next().unwrap();
let result = <usize as serde::Deserialize>::deserialize(first_doc);
assert_eq!(0, result.unwrap());
let second_doc = de.next().unwrap();
let result = <usize as serde::Deserialize>::deserialize(second_doc);
let expected =
"did not find expected node content at line 4 column 1, while parsing a block node";
assert_eq!(expected, result.unwrap_err().to_string());
}
#[test]
fn test_missing_enum_tag() {
#[derive(Deserialize, Debug)]
pub enum E {
V(usize),
}
let yaml = indoc! {r#"
"V": 16
"other": 32
"#};
let expected = "invalid type: map, expected a YAML tag starting with '!'";
test_error::<E>(yaml, expected);
}
#[test]
fn test_serialize_nested_enum() {
#[derive(Serialize, Debug)]
pub enum Outer {
Inner(Inner),
}
#[derive(Serialize, Debug)]
pub enum Inner {
Newtype(usize),
Tuple(usize, usize),
Struct { x: usize },
}
let expected = "serializing nested enums in YAML is not supported yet";
let e = Outer::Inner(Inner::Newtype(0));
let error = serde_yaml::to_string(&e).unwrap_err();
assert_eq!(error.to_string(), expected);
let e = Outer::Inner(Inner::Tuple(0, 0));
let error = serde_yaml::to_string(&e).unwrap_err();
assert_eq!(error.to_string(), expected);
let e = Outer::Inner(Inner::Struct { x: 0 });
let error = serde_yaml::to_string(&e).unwrap_err();
assert_eq!(error.to_string(), expected);
let e = Value::Tagged(Box::new(TaggedValue {
tag: Tag::new("Outer"),
value: Value::Tagged(Box::new(TaggedValue {
tag: Tag::new("Inner"),
value: Value::Null,
})),
}));
let error = serde_yaml::to_string(&e).unwrap_err();
assert_eq!(error.to_string(), expected);
}
#[test]
fn test_deserialize_nested_enum() {
#[derive(Deserialize, Debug)]
pub enum Outer {
Inner(Inner),
}
#[derive(Deserialize, Debug)]
pub enum Inner {
Variant(Vec<usize>),
}
let yaml = indoc! {"
---
!Inner []
"};
let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
test_error::<Outer>(yaml, expected);
let yaml = indoc! {"
---
!Variant []
"};
let expected = "unknown variant `Variant`, expected `Inner`";
test_error::<Outer>(yaml, expected);
let yaml = indoc! {"
---
!Inner !Variant []
"};
let expected = "deserializing nested enum in Outer::Inner from YAML is not supported yet at line 2 column 1";
test_error::<Outer>(yaml, expected);
}
#[test]
fn test_variant_not_a_seq() {
#[derive(Deserialize, Debug)]
pub enum E {
V(usize),
}
let yaml = indoc! {"
---
!V
value: 0
"};
let expected = "invalid type: map, expected usize at line 2 column 1";
test_error::<E>(yaml, expected);
}
#[test]
fn test_struct_from_sequence() {
#[derive(Deserialize, Debug)]
pub struct Struct {
pub x: usize,
pub y: usize,
}
let yaml = indoc! {"
[0, 0]
"};
let expected = "invalid type: sequence, expected struct Struct";
test_error::<Struct>(yaml, expected);
}
#[test]
fn test_bad_bool() {
let yaml = indoc! {"
---
!!bool str
"};
let expected = "invalid value: string \"str\", expected a boolean at line 2 column 1";
test_error::<bool>(yaml, expected);
}
#[test]
fn test_bad_int() {
let yaml = indoc! {"
---
!!int str
"};
let expected = "invalid value: string \"str\", expected an integer at line 2 column 1";
test_error::<i64>(yaml, expected);
}
#[test]
fn test_bad_float() {
let yaml = indoc! {"
---
!!float str
"};
let expected = "invalid value: string \"str\", expected a float at line 2 column 1";
test_error::<f64>(yaml, expected);
}
#[test]
fn test_bad_null() {
let yaml = indoc! {"
---
!!null str
"};
let expected = "invalid value: string \"str\", expected null at line 2 column 1";
test_error::<()>(yaml, expected);
}
#[test]
fn test_short_tuple() {
let yaml = indoc! {"
---
[0, 0]
"};
let expected = "invalid length 2, expected a tuple of size 3 at line 2 column 1";
test_error::<(u8, u8, u8)>(yaml, expected);
}
#[test]
fn test_long_tuple() {
let yaml = indoc! {"
---
[0, 0, 0]
"};
let expected = "invalid length 3, expected sequence of 2 elements at line 2 column 1";
test_error::<(u8, u8)>(yaml, expected);
}
#[test]
fn test_invalid_scalar_type() {
#[derive(Deserialize, Debug)]
pub struct S {
pub x: [i32; 1],
}
let yaml = "x: ''\n";
let expected = "x: invalid type: string \"\", expected an array of length 1 at line 1 column 4";
test_error::<S>(yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_objects() {
#[derive(Deserialize, Debug)]
pub struct S {
pub x: Option<Box<S>>,
}
let yaml = "&a {'x': *a}";
let expected = "recursion limit exceeded";
test_error::<S>(yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_arrays() {
#[derive(Deserialize, Debug)]
pub struct S(pub usize, pub Option<Box<S>>);
let yaml = "&a [0, *a]";
let expected = "recursion limit exceeded";
test_error::<S>(yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_infinite_recursion_newtype() {
#[derive(Deserialize, Debug)]
pub struct S(pub Option<Box<S>>);
let yaml = "&a [*a]";
let expected = "recursion limit exceeded";
test_error::<S>(yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_finite_recursion_objects() {
#[derive(Deserialize, Debug)]
pub struct S {
pub x: Option<Box<S>>,
}
let yaml = "{'x':".repeat(1_000) + &"}".repeat(1_000);
let expected = "recursion limit exceeded at line 1 column 641";
test_error::<S>(&yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_finite_recursion_arrays() {
#[derive(Deserialize, Debug)]
pub struct S(pub usize, pub Option<Box<S>>);
let yaml = "[0, ".repeat(1_000) + &"]".repeat(1_000);
let expected = "recursion limit exceeded at line 1 column 513";
test_error::<S>(&yaml, expected);
}
#[cfg(not(miri))]
#[test]
fn test_billion_laughs() {
#[derive(Debug)]
struct X;
impl<'de> Deserialize<'de> for X {
fn deserialize<D>(deserializer: D) -> Result<X, D::Error>
where
D: serde::Deserializer<'de>,
{
impl<'de> Visitor<'de> for X {
type Value = X;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("exponential blowup")
}
fn visit_unit<E>(self) -> Result<X, E> {
Ok(X)
}
fn visit_seq<S>(self, mut seq: S) -> Result<X, S::Error>
where
S: SeqAccess<'de>,
{
while let Some(X) = seq.next_element()? {}
Ok(X)
}
}
deserializer.deserialize_any(X)
}
}
let yaml = indoc! {"
a: &a ~
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
"};
let expected = "repetition limit exceeded";
test_error::<BTreeMap<String, X>>(yaml, expected);
}
#[test]
fn test_duplicate_keys() {
let yaml = indoc! {"
---
thing: true
thing: false
"};
let expected = "duplicate entry with key \"thing\" at line 2 column 1";
test_error::<Value>(yaml, expected);
let yaml = indoc! {"
---
null: true
~: false
"};
let expected = "duplicate entry with null key at line 2 column 1";
test_error::<Value>(yaml, expected);
let yaml = indoc! {"
---
99: true
99: false
"};
let expected = "duplicate entry with key 99 at line 2 column 1";
test_error::<Value>(yaml, expected);
let yaml = indoc! {"
---
{}: true
{}: false
"};
let expected = "duplicate entry in YAML map at line 2 column 1";
test_error::<Value>(yaml, expected);
}