aboutsummaryrefslogtreecommitdiff
path: root/tests/serde.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/serde.rs')
-rw-r--r--tests/serde.rs496
1 files changed, 496 insertions, 0 deletions
diff --git a/tests/serde.rs b/tests/serde.rs
new file mode 100644
index 0000000..e4d88fc
--- /dev/null
+++ b/tests/serde.rs
@@ -0,0 +1,496 @@
+extern crate serde;
+extern crate toml;
+#[macro_use]
+extern crate serde_derive;
+
+use std::collections::{BTreeMap, HashSet};
+use serde::{Deserialize, Deserializer};
+
+use toml::Value;
+use toml::Value::{Table, Integer, Array, Float};
+
+macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(t) => t,
+ Err(e) => panic!("{} failed with {}", stringify!($e), e),
+ })
+}
+
+macro_rules! equivalent {
+ ($literal:expr, $toml:expr,) => ({
+ let toml = $toml;
+ let literal = $literal;
+
+ // In/out of Value is equivalent
+ println!("try_from");
+ assert_eq!(t!(Value::try_from(literal.clone())), toml);
+ println!("try_into");
+ assert_eq!(literal, t!(toml.clone().try_into()));
+
+ // Through a string equivalent
+ println!("to_string(literal)");
+ assert_eq!(t!(toml::to_string(&literal)), toml.to_string());
+ println!("to_string(toml)");
+ assert_eq!(t!(toml::to_string(&toml)), toml.to_string());
+ println!("literal, from_str(toml)");
+ assert_eq!(literal, t!(toml::from_str(&toml.to_string())));
+ println!("toml, from_str(toml)");
+ assert_eq!(toml, t!(toml::from_str(&toml.to_string())));
+ })
+}
+
+macro_rules! error {
+ ($ty:ty, $toml:expr, $error:expr) => ({
+ println!("attempting parsing");
+ match toml::from_str::<$ty>(&$toml.to_string()) {
+ Ok(_) => panic!("successful"),
+ Err(e) => {
+ assert!(e.to_string().contains($error),
+ "bad error: {}", e);
+ }
+ }
+
+ println!("attempting toml decoding");
+ match $toml.try_into::<$ty>() {
+ Ok(_) => panic!("successful"),
+ Err(e) => {
+ assert!(e.to_string().contains($error),
+ "bad error: {}", e);
+ }
+ }
+ })
+}
+
+macro_rules! decode( ($t:expr) => ({
+ t!($t.try_into())
+}) );
+
+macro_rules! map( ($($k:ident: $v:expr),*) => ({
+ let mut _m = BTreeMap::new();
+ $(_m.insert(stringify!($k).to_string(), $v);)*
+ _m
+}) );
+
+#[test]
+fn smoke() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: isize }
+
+ equivalent!(
+ Foo { a: 2 },
+ Table(map! { a: Integer(2) }),
+ );
+}
+
+#[test]
+fn smoke_hyphen() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo {
+ a_b: isize,
+ }
+
+ equivalent! {
+ Foo { a_b: 2 },
+ Table(map! { a_b: Integer(2) }),
+ }
+
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo2 {
+ #[serde(rename = "a-b")]
+ a_b: isize,
+ }
+
+ let mut m = BTreeMap::new();
+ m.insert("a-b".to_string(), Integer(2));
+ equivalent! {
+ Foo2 { a_b: 2 },
+ Table(m),
+ }
+}
+
+#[test]
+fn nested() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: isize, b: Bar }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Bar { a: String }
+
+ equivalent! {
+ Foo { a: 2, b: Bar { a: "test".to_string() } },
+ Table(map! {
+ a: Integer(2),
+ b: Table(map! {
+ a: Value::String("test".to_string())
+ })
+ }),
+ }
+}
+
+#[test]
+fn application_decode_error() {
+ #[derive(PartialEq, Debug)]
+ struct Range10(usize);
+ impl Deserialize for Range10 {
+ fn deserialize<D: Deserializer>(d: D) -> Result<Range10, D::Error> {
+ let x: usize = try!(Deserialize::deserialize(d));
+ if x > 10 {
+ Err(serde::de::Error::custom("more than 10"))
+ } else {
+ Ok(Range10(x))
+ }
+ }
+ }
+ let d_good = Integer(5);
+ let d_bad1 = Value::String("not an isize".to_string());
+ let d_bad2 = Integer(11);
+
+ assert_eq!(Range10(5), d_good.try_into().unwrap());
+
+ let err1: Result<Range10, _> = d_bad1.try_into();
+ assert!(err1.is_err());
+ let err2: Result<Range10, _> = d_bad2.try_into();
+ assert!(err2.is_err());
+}
+
+#[test]
+fn array() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: Vec<isize> }
+
+ equivalent! {
+ Foo { a: vec![1, 2, 3, 4] },
+ Table(map! {
+ a: Array(vec![
+ Integer(1),
+ Integer(2),
+ Integer(3),
+ Integer(4)
+ ])
+ }),
+ };
+}
+
+#[test]
+fn inner_structs_with_options() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo {
+ a: Option<Box<Foo>>,
+ b: Bar,
+ }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Bar {
+ a: String,
+ b: f64,
+ }
+
+ equivalent! {
+ Foo {
+ a: Some(Box::new(Foo {
+ a: None,
+ b: Bar { a: "foo".to_string(), b: 4.5 },
+ })),
+ b: Bar { a: "bar".to_string(), b: 1.0 },
+ },
+ Table(map! {
+ a: Table(map! {
+ b: Table(map! {
+ a: Value::String("foo".to_string()),
+ b: Float(4.5)
+ })
+ }),
+ b: Table(map! {
+ a: Value::String("bar".to_string()),
+ b: Float(1.0)
+ })
+ }),
+ }
+}
+
+#[test]
+fn hashmap() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo {
+ set: HashSet<char>,
+ map: BTreeMap<String, isize>,
+ }
+
+ equivalent! {
+ Foo {
+ map: {
+ let mut m = BTreeMap::new();
+ m.insert("foo".to_string(), 10);
+ m.insert("bar".to_string(), 4);
+ m
+ },
+ set: {
+ let mut s = HashSet::new();
+ s.insert('a');
+ s
+ },
+ },
+ Table(map! {
+ map: Table(map! {
+ foo: Integer(10),
+ bar: Integer(4)
+ }),
+ set: Array(vec![Value::String("a".to_string())])
+ }),
+ }
+}
+
+#[test]
+fn table_array() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: Vec<Bar>, }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Bar { a: isize }
+
+ equivalent! {
+ Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] },
+ Table(map! {
+ a: Array(vec![
+ Table(map!{ a: Integer(1) }),
+ Table(map!{ a: Integer(2) }),
+ ])
+ }),
+ }
+}
+
+#[test]
+fn type_errors() {
+ #[derive(Deserialize)]
+ #[allow(dead_code)]
+ struct Foo { bar: isize }
+
+ error! {
+ Foo,
+ Table(map! {
+ bar: Value::String("a".to_string())
+ }),
+ "invalid type: string \"a\", expected isize for key `bar`"
+ }
+
+ #[derive(Deserialize)]
+ #[allow(dead_code)]
+ struct Bar { foo: Foo }
+
+ error! {
+ Bar,
+ Table(map! {
+ foo: Table(map! {
+ bar: Value::String("a".to_string())
+ })
+ }),
+ "invalid type: string \"a\", expected isize for key `foo.bar`"
+ }
+}
+
+#[test]
+fn missing_errors() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug)]
+ struct Foo { bar: isize }
+
+ error! {
+ Foo,
+ Table(map! { }),
+ "missing field `bar`"
+ }
+}
+
+#[test]
+fn parse_enum() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: E }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ #[serde(untagged)]
+ enum E {
+ Bar(isize),
+ Baz(String),
+ Last(Foo2),
+ }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo2 {
+ test: String,
+ }
+
+ equivalent! {
+ Foo { a: E::Bar(10) },
+ Table(map! { a: Integer(10) }),
+ }
+
+ equivalent! {
+ Foo { a: E::Baz("foo".to_string()) },
+ Table(map! { a: Value::String("foo".to_string()) }),
+ }
+
+ equivalent! {
+ Foo { a: E::Last(Foo2 { test: "test".to_string() }) },
+ Table(map! { a: Table(map! { test: Value::String("test".to_string()) }) }),
+ }
+}
+
+// #[test]
+// fn unused_fields() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: isize }
+//
+// let v = Foo { a: 2 };
+// let mut d = Decoder::new(Table(map! {
+// a, Integer(2),
+// b, Integer(5)
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, Some(Table(map! {
+// b, Integer(5)
+// })));
+// }
+//
+// #[test]
+// fn unused_fields2() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: Bar }
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Bar { a: isize }
+//
+// let v = Foo { a: Bar { a: 2 } };
+// let mut d = Decoder::new(Table(map! {
+// a, Table(map! {
+// a, Integer(2),
+// b, Integer(5)
+// })
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, Some(Table(map! {
+// a, Table(map! {
+// b, Integer(5)
+// })
+// })));
+// }
+//
+// #[test]
+// fn unused_fields3() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: Bar }
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Bar { a: isize }
+//
+// let v = Foo { a: Bar { a: 2 } };
+// let mut d = Decoder::new(Table(map! {
+// a, Table(map! {
+// a, Integer(2)
+// })
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, None);
+// }
+//
+// #[test]
+// fn unused_fields4() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: BTreeMap<String, String> }
+//
+// let v = Foo { a: map! { a, "foo".to_string() } };
+// let mut d = Decoder::new(Table(map! {
+// a, Table(map! {
+// a, Value::String("foo".to_string())
+// })
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, None);
+// }
+//
+// #[test]
+// fn unused_fields5() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: Vec<String> }
+//
+// let v = Foo { a: vec!["a".to_string()] };
+// let mut d = Decoder::new(Table(map! {
+// a, Array(vec![Value::String("a".to_string())])
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, None);
+// }
+//
+// #[test]
+// fn unused_fields6() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: Option<Vec<String>> }
+//
+// let v = Foo { a: Some(vec![]) };
+// let mut d = Decoder::new(Table(map! {
+// a, Array(vec![])
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, None);
+// }
+//
+// #[test]
+// fn unused_fields7() {
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Foo { a: Vec<Bar> }
+// #[derive(Serialize, Deserialize, PartialEq, Debug)]
+// struct Bar { a: isize }
+//
+// let v = Foo { a: vec![Bar { a: 1 }] };
+// let mut d = Decoder::new(Table(map! {
+// a, Array(vec![Table(map! {
+// a, Integer(1),
+// b, Integer(2)
+// })])
+// }));
+// assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
+//
+// assert_eq!(d.toml, Some(Table(map! {
+// a, Array(vec![Table(map! {
+// b, Integer(2)
+// })])
+// })));
+// }
+
+#[test]
+fn empty_arrays() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: Vec<Bar> }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Bar;
+
+ equivalent! {
+ Foo { a: vec![] },
+ Table(map! {a: Array(Vec::new())}),
+ }
+}
+
+#[test]
+fn empty_arrays2() {
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Foo { a: Option<Vec<Bar>> }
+ #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+ struct Bar;
+
+ equivalent! {
+ Foo { a: None },
+ Table(map! {}),
+ }
+
+ equivalent!{
+ Foo { a: Some(vec![]) },
+ Table(map! { a: Array(vec![]) }),
+ }
+}
+
+#[test]
+fn extra_keys() {
+ #[derive(Serialize, Deserialize)]
+ struct Foo { a: isize }
+
+ let toml = Table(map! { a: Integer(2), b: Integer(2) });
+ assert!(toml.clone().try_into::<Foo>().is_ok());
+ assert!(toml::from_str::<Foo>(&toml.to_string()).is_ok());
+}