diff options
| -rw-r--r-- | .travis.yml | 2 | ||||
| -rw-r--r-- | Cargo.toml | 8 | ||||
| -rw-r--r-- | build.rs | 35 | ||||
| -rw-r--r-- | src/de.rs | 3 | ||||
| -rw-r--r-- | src/ser.rs | 3 | ||||
| -rw-r--r-- | tests/serde_/mod.rs | 209 | ||||
| -rw-r--r-- | tests/serde_tests.rs.in | 4 | ||||
| -rw-r--r-- | tests/tests.rs | 2 |
8 files changed, 265 insertions, 1 deletions
diff --git a/.travis.yml b/.travis.yml index bdc9561..2c31be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_script: script: - | travis-cargo build && - travis-cargo test && + travis-cargo test -- --features serde_tests && travis-cargo --only stable doc after_success: - travis-cargo --only stable doc-upload @@ -7,6 +7,10 @@ license = "MIT" repository = "https://github.com/ebarnard/rust-plist/" documentation = "https://ebarnard.github.io/rust-plist/" keywords = ["plist", "parser"] +build = "build.rs" + +[features] +serde_tests = ["serde_codegen", "syntex"] [dependencies] rustc-serialize = "0.3.16" @@ -14,3 +18,7 @@ xml-rs = "0.2.2" byteorder = "0.4.2" chrono = "0.2.17" serde = "0.6.6" + +[build-dependencies] +serde_codegen = { version = "0.6.6", optional = true } +syntex = { version = "0.22.0", optional = true } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..df4282a --- /dev/null +++ b/build.rs @@ -0,0 +1,35 @@ +#[cfg(feature = "serde_tests")] +extern crate syntex; + +#[cfg(feature = "serde_tests")] +extern crate serde_codegen; + +#[cfg(feature = "serde_tests")] +mod serde_tests { + use std::env; + use std::path::Path; + + use syntex; + use serde_codegen; + + pub fn build() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("tests/serde_tests.rs.in"); + let dst = Path::new(&out_dir).join("serde_tests.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(not(feature = "serde_tests"))] +mod serde_tests { + pub fn build() {} +} + +fn main() { + serde_tests::build() +} @@ -1,3 +1,6 @@ +// Tests for the serializer and deserializer are located in tests/serde_/mod.rs. +// They can be run with `cargo test --features serde_tests`. + use serde::de::{Deserializer as SerdeDeserializer, Error as SerdeError, Visitor, SeqVisitor, MapVisitor, VariantVisitor, Deserialize, EnumVisitor}; use std::iter::Peekable; @@ -1,3 +1,6 @@ +// Tests for the serializer and deserializer are located in tests/serde_/mod.rs. +// They can be run with `cargo test --features serde_tests`. + use serde::ser::{MapVisitor, Serialize, Serializer as SerdeSerializer, SeqVisitor}; use {EventWriter, PlistEvent}; diff --git a/tests/serde_/mod.rs b/tests/serde_/mod.rs new file mode 100644 index 0000000..a2cbd41 --- /dev/null +++ b/tests/serde_/mod.rs @@ -0,0 +1,209 @@ +use plist::{Deserializer, EventWriter, PlistEvent, Serializer}; +use plist::PlistEvent::*; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +struct VecWriter { + events: Vec<PlistEvent>, +} + +impl VecWriter { + pub fn new() -> VecWriter { + VecWriter { events: Vec::new() } + } + + pub fn into_inner(self) -> Vec<PlistEvent> { + self.events + } +} + +impl EventWriter for VecWriter { + fn write(&mut self, event: &PlistEvent) -> Result<(), ()> { + self.events.push(event.clone()); + Ok(()) + } +} + +fn new_serializer() -> Serializer<VecWriter> { + Serializer::new(VecWriter::new()) +} + +fn new_deserializer(events: Vec<PlistEvent>) -> Deserializer<Vec<Result<PlistEvent, ()>>, ()> { + let result_events = events.into_iter().map(|e| Ok(e)).collect(); + Deserializer::new(result_events) +} + +fn assert_roundtrip<T>(obj: T, comparison: Option<&[PlistEvent]>) + where T: Debug + Deserialize + PartialEq + Serialize +{ + let mut se = new_serializer(); + + obj.serialize(&mut se).unwrap(); + + let events = se.into_inner().into_inner(); + + match comparison { + Some(comparison) => { + assert_eq!(&events[..], comparison); + } + None => (), + } + + let mut de = new_deserializer(events); + + let new_obj = T::deserialize(&mut de).unwrap(); + + assert_eq!(new_obj, obj); +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +enum Animal { + Cow, + Dog(DogOuter), + Frog(Result<String, bool>, Vec<f64>), + Cat { + age: usize, + name: String, + firmware: Option<Vec<u8>>, + }, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct DogOuter { + inner: Vec<DogInner>, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct DogInner { + a: (), + b: usize, + c: Vec<String>, +} + +#[test] +fn cow() { + let cow = Animal::Cow; + + let comparison = &[StartDictionary(Some(1)), + StringValue("Cow".to_owned()), + StringValue("".to_owned()), + EndDictionary]; + + assert_roundtrip(cow, Some(comparison)); +} + + +#[test] +fn dog() { + let dog = Animal::Dog(DogOuter { + inner: vec![DogInner { + a: (), + b: 12, + c: vec!["a".to_string(), "b".to_string()], + }], + }); + + let comparison = &[StartDictionary(Some(1)), + StringValue("Dog".to_owned()), + StartDictionary(Some(1)), + StringValue("inner".to_owned()), + StartArray(Some(1)), + StartDictionary(Some(3)), + StringValue("a".to_owned()), + StringValue("".to_owned()), + StringValue("b".to_owned()), + IntegerValue(12), + StringValue("c".to_owned()), + StartArray(Some(2)), + StringValue("a".to_owned()), + StringValue("b".to_owned()), + EndArray, + EndDictionary, + EndArray, + EndDictionary, + EndDictionary]; + + assert_roundtrip(dog, Some(comparison)); +} + + +#[test] +fn frog() { + let frog = Animal::Frog(Ok("hello".to_owned()), + vec![1.0, 2.0, 3.14159, 0.000000001, 1.27e31]); + + let comparison = &[StartDictionary(Some(1)), + StringValue("Frog".to_owned()), + StartArray(Some(2)), + StartDictionary(Some(1)), + StringValue("Ok".to_owned()), + StringValue("hello".to_owned()), + EndDictionary, + StartArray(Some(5)), + RealValue(1.0), + RealValue(2.0), + RealValue(3.14159), + RealValue(0.000000001), + RealValue(1.27e31), + EndArray, + EndArray, + EndDictionary]; + + assert_roundtrip(frog, Some(comparison)); +} + + +#[test] +fn cat() { + let cat = Animal::Cat { + age: 12, + name: "Paws".to_owned(), + firmware: Some(vec![0, 1, 2, 3, 4, 5, 6, 7, 8]), + }; + + let comparison = &[StartDictionary(Some(1)), + StringValue("Cat".to_owned()), + StartDictionary(Some(3)), + StringValue("age".to_owned()), + IntegerValue(12), + StringValue("name".to_owned()), + StringValue("Paws".to_owned()), + StringValue("firmware".to_owned()), + StartDictionary(Some(1)), + StringValue("Some".to_owned()), + StartArray(Some(9)), + IntegerValue(0), + IntegerValue(1), + IntegerValue(2), + IntegerValue(3), + IntegerValue(4), + IntegerValue(5), + IntegerValue(6), + IntegerValue(7), + IntegerValue(8), + EndArray, + EndDictionary, + EndDictionary, + EndDictionary]; + + assert_roundtrip(cat, Some(comparison)); +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct NewtypeStruct(NewtypeInner); + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct NewtypeInner(u8, u8, u8); + +#[test] +fn newtype_struct() { + let newtype = NewtypeStruct(NewtypeInner(34, 32, 13)); + + let comparison = &[StartArray(Some(3)), + IntegerValue(34), + IntegerValue(32), + IntegerValue(13), + EndArray]; + + assert_roundtrip(newtype, Some(comparison)); +} diff --git a/tests/serde_tests.rs.in b/tests/serde_tests.rs.in new file mode 100644 index 0000000..8e04ab0 --- /dev/null +++ b/tests/serde_tests.rs.in @@ -0,0 +1,4 @@ +extern crate serde; +extern crate plist; + +mod serde_; diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..0aaf77c --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "serde_tests")] +include!(concat!(env!("OUT_DIR"), "/serde_tests.rs")); |
