Add an example to the Configure trait

This commit is contained in:
Markus Westerlind 2017-11-03 16:12:43 +01:00
parent 1b9a096fa7
commit aad7a7987f
10 changed files with 157 additions and 186 deletions

View File

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use de::Deserializer;
use ser::Serializer;
@ -47,20 +47,8 @@ pub fn assert_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
assert_tokens_readable(value, tokens, None);
}
// Not public API
#[doc(hidden)]
/// Runs both `assert_ser_tokens` and `assert_de_tokens`.
///
/// See: `assert_tokens`
pub fn assert_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
where
T: Serialize + Deserialize<'de> + PartialEq + Debug,
{
assert_ser_tokens_readable(value, tokens, human_readable);
assert_de_tokens_readable(value, tokens, human_readable);
assert_ser_tokens(value, tokens);
assert_de_tokens(value, tokens);
}
/// Asserts that `value` serializes to the given `tokens`.
@ -96,19 +84,7 @@ pub fn assert_ser_tokens<T>(value: &T, tokens: &[Token])
where
T: Serialize,
{
assert_ser_tokens_readable(value, tokens, None)
}
// Not public API
#[doc(hidden)]
/// Asserts that `value` serializes to the given `tokens`.
///
/// See: `assert_ser_tokens`
pub fn assert_ser_tokens_readable<T>(value: &T, tokens: &[Token], human_readable: Option<bool>)
where
T: Serialize,
{
let mut ser = Serializer::readable(tokens, human_readable);
let mut ser = Serializer::new(tokens);
match value.serialize(&mut ser) {
Ok(_) => {}
Err(err) => panic!("value failed to serialize: {}", err),
@ -207,16 +183,7 @@ pub fn assert_de_tokens<'de, T>(value: &T, tokens: &'de [Token])
where
T: Deserialize<'de> + PartialEq + Debug,
{
assert_de_tokens_readable(value, tokens, None)
}
// Not public API
#[doc(hidden)]
pub fn assert_de_tokens_readable<'de, T>(value: &T, tokens: &'de [Token], human_readable: Option<bool>)
where
T: Deserialize<'de> + PartialEq + Debug,
{
let mut de = Deserializer::readable(tokens, human_readable);
let mut de = Deserializer::new(tokens);
match T::deserialize(&mut de) {
Ok(v) => assert_eq!(v, *value),
Err(e) => panic!("tokens failed to deserialize: {}", e),

View File

@ -4,19 +4,85 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
SerializeTuple, SerializeTupleStruct, SerializeTupleVariant};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Readable<T: ?Sized>(T);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Compact<T: ?Sized>(T);
pub trait Configure {
fn readable(&self) -> Readable<&Self> {
/// Trait which lets values mark wheter they should serialize or deserialize to or from their
/// human-readable or compact representation.
///
/// ```
/// extern crate serde;
/// extern crate serde_test;
///
/// use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// use serde_test::{Configure, Token, assert_tokens};
///
/// #[derive(Debug, PartialEq)]
/// struct Example(u8, u8);
///
/// impl Serialize for Example {
/// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
/// where S: Serializer,
/// {
/// if serializer.is_human_readable() {
/// format!("{}.{}", self.0, self.1).serialize(serializer)
/// } else {
/// (self.0, self.1).serialize(serializer)
/// }
/// }
/// }
///
/// impl<'de> Deserialize<'de> for Example {
/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
/// where D: Deserializer<'de>,
/// {
/// use serde::de::Error;
/// if deserializer.is_human_readable() {
/// let s = String::deserialize(deserializer)?;
/// let parts: Vec<_> = s.split('.').collect();
/// Ok(Example(
/// parts[0].parse().map_err(D::Error::custom)?,
/// parts[1].parse().map_err(D::Error::custom)?,
/// ))
/// } else {
/// let (x, y) = Deserialize::deserialize(deserializer)?;
/// Ok(Example(x, y))
/// }
/// }
/// }
///
/// fn main() {
/// assert_tokens(
/// &Example(1, 0).compact(),
/// &[
/// Token::Tuple { len: 2 },
/// Token::U8(1),
/// Token::U8(0),
/// Token::TupleEnd,
/// ],
/// );
/// assert_tokens(
/// &Example(1, 0).readable(),
/// &[
/// Token::Str("1.0"),
/// ],
/// );
/// }
/// ```
pub trait Configure : Sized {
/// Marks `self` as using `is_human_readable == true`
fn readable(self) -> Readable<Self> {
Readable(self)
}
fn compact(&self) -> Compact<&Self> {
/// Marks `self` as using `is_human_readable == false`
fn compact(self) -> Compact<Self> {
Compact(self)
}
}
impl<T: ?Sized> Configure for T {}
impl<T> Configure for T {}
impl<T: ?Sized> Serialize for Readable<T>
where

View File

@ -16,7 +16,6 @@ use token::Token;
#[derive(Debug)]
pub struct Deserializer<'de> {
tokens: &'de [Token],
is_human_readable: Option<bool>,
}
macro_rules! assert_next_token {
@ -49,13 +48,7 @@ macro_rules! end_of_tokens {
impl<'de> Deserializer<'de> {
pub fn new(tokens: &'de [Token]) -> Self {
Deserializer::readable(tokens, None)
}
// Not public API
#[doc(hidden)]
pub fn readable(tokens: &'de [Token], is_human_readable: Option<bool>) -> Self {
Deserializer { tokens: tokens, is_human_readable: is_human_readable }
Deserializer { tokens: tokens }
}
fn peek_token_opt(&self) -> Option<Token> {
@ -373,15 +366,10 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
}
fn is_human_readable(&self) -> bool {
match self.is_human_readable {
Some(is) => is,
None => {
panic!("There is no serde_test API currently for testing types \
that have different human-readable and compact \
representation. See \
https://github.com/serde-rs/serde/issues/1065.");
}
}
panic!(
"Types which have different human-readable and compact representations\
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}

View File

@ -169,14 +169,10 @@ mod token;
mod assert;
pub use token::Token;
pub use assert::{assert_tokens, assert_ser_tokens, assert_ser_tokens_error,
assert_de_tokens, assert_de_tokens_error};
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
assert_ser_tokens_error, assert_tokens};
pub use configure::{Configure, Compact, Readable};
// Not public API.
#[doc(hidden)]
pub use assert::{assert_tokens_readable, assert_de_tokens_readable, assert_ser_tokens_readable};
pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]

View File

@ -15,19 +15,12 @@ use token::Token;
#[derive(Debug)]
pub struct Serializer<'a> {
tokens: &'a [Token],
is_human_readable: Option<bool>,
}
impl<'a> Serializer<'a> {
/// Creates the serializer.
pub fn new(tokens: &'a [Token]) -> Self {
Serializer::readable(tokens, None)
}
// Not public API
#[doc(hidden)]
pub fn readable(tokens: &'a [Token], is_human_readable: Option<bool>) -> Self {
Serializer { tokens: tokens, is_human_readable: is_human_readable }
Serializer { tokens: tokens }
}
/// Pulls the next token off of the serializer, ignoring it.
@ -254,10 +247,16 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Seq { len });
Ok(Variant { ser: self, end: Token::SeqEnd })
Ok(Variant {
ser: self,
end: Token::SeqEnd,
})
} else {
assert_next_token!(self, TupleVariant { name, variant, len });
Ok(Variant { ser: self, end: Token::TupleVariantEnd })
Ok(Variant {
ser: self,
end: Token::TupleVariantEnd,
})
}
}
@ -283,23 +282,24 @@ impl<'s, 'a> ser::Serializer for &'s mut Serializer<'a> {
assert_next_token!(self, Str(variant));
let len = Some(len);
assert_next_token!(self, Map { len });
Ok(Variant { ser: self, end: Token::MapEnd })
Ok(Variant {
ser: self,
end: Token::MapEnd,
})
} else {
assert_next_token!(self, StructVariant { name, variant, len });
Ok(Variant { ser: self, end: Token::StructVariantEnd })
Ok(Variant {
ser: self,
end: Token::StructVariantEnd,
})
}
}
fn is_human_readable(&self) -> bool {
match self.is_human_readable {
Some(is) => is,
None => {
panic!("There is no serde_test API currently for testing types \
that have different human-readable and compact \
representation. See \
https://github.com/serde-rs/serde/issues/1065.");
}
}
panic!(
"Types which have different human-readable and compact representations\
must explicitly mark their test cases with `serde_test::Configure`"
);
}
}

View File

@ -29,7 +29,7 @@ extern crate fnv;
use self::fnv::FnvHasher;
extern crate serde_test;
use self::serde_test::{Token, assert_de_tokens, assert_de_tokens_error, assert_de_tokens_readable};
use self::serde_test::{assert_de_tokens, assert_de_tokens_error, Configure, Token};
#[macro_use]
mod macros;
@ -49,16 +49,14 @@ struct TupleStruct(i32, i32, i32);
struct Struct {
a: i32,
b: i32,
#[serde(skip_deserializing)]
c: i32,
#[serde(skip_deserializing)] c: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructDenyUnknown {
a: i32,
#[serde(skip_deserializing)]
b: i32,
#[serde(skip_deserializing)] b: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@ -79,15 +77,13 @@ impl Default for StructDefault<String> {
#[derive(PartialEq, Debug, Deserialize)]
struct StructSkipAll {
#[serde(skip_deserializing)]
a: i32,
#[serde(skip_deserializing)] a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
struct StructSkipAllDenyUnknown {
#[serde(skip_deserializing)]
a: i32,
#[serde(skip_deserializing)] a: i32,
}
#[derive(PartialEq, Debug, Deserialize)]
@ -112,7 +108,7 @@ enum EnumSkipAll {
macro_rules! declare_tests {
(
readable: $readable:tt
$readable:tt
$($name:ident { $($value:expr => $tokens:expr,)+ })+
) => {
$(
@ -120,7 +116,7 @@ macro_rules! declare_tests {
fn $name() {
$(
// Test ser/de roundtripping
assert_de_tokens_readable(&$value, $tokens, Some($readable));
assert_de_tokens(&$value.$readable(), $tokens);
// Test that the tokens are ignorable
assert_de_tokens_ignore($tokens);
@ -168,13 +164,11 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
Token::Map { len: Some(2) },
Token::Str("a"),
Token::I32(1),
Token::Str("ignored"),
]
.into_iter()
.chain(ignorable_tokens.to_vec().into_iter())
.chain(vec![Token::MapEnd].into_iter())
.collect();
].into_iter()
.chain(ignorable_tokens.to_vec().into_iter())
.chain(vec![Token::MapEnd].into_iter())
.collect();
let mut de = serde_test::Deserializer::new(&concated_tokens);
let base = IgnoreBase::deserialize(&mut de).unwrap();
@ -774,7 +768,8 @@ declare_tests! {
}
declare_tests! {
readable: true
readable
test_net_ipv4addr_readable {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
@ -792,7 +787,8 @@ declare_tests! {
}
declare_tests! {
readable: false
compact
test_net_ipv4addr_compact {
net::Ipv4Addr::from(*b"1234") => &seq![
Token::Tuple { len: 4 },

View File

@ -9,10 +9,8 @@
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_test;
use serde_test::{Token, assert_de_tokens};
use serde_test::{assert_de_tokens, Token};
#[test]
fn test_variant_identifier() {
@ -51,8 +49,7 @@ fn test_unit_fallthrough() {
enum F {
Aaa,
Bbb,
#[serde(other)]
Other,
#[serde(other)] Other,
}
assert_de_tokens(&F::Other, &[Token::Str("x")]);

View File

@ -9,8 +9,6 @@
#[macro_use]
extern crate serde_derive;
extern crate serde;
mod remote {
pub struct Unit;
@ -87,32 +85,23 @@ mod remote {
#[derive(Serialize, Deserialize)]
struct Test {
#[serde(with = "UnitDef")]
unit: remote::Unit,
#[serde(with = "UnitDef")] unit: remote::Unit,
#[serde(with = "PrimitivePrivDef")]
primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePrivDef")] primitive_priv: remote::PrimitivePriv,
#[serde(with = "PrimitivePubDef")]
primitive_pub: remote::PrimitivePub,
#[serde(with = "PrimitivePubDef")] primitive_pub: remote::PrimitivePub,
#[serde(with = "NewtypePrivDef")]
newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePrivDef")] newtype_priv: remote::NewtypePriv,
#[serde(with = "NewtypePubDef")]
newtype_pub: remote::NewtypePub,
#[serde(with = "NewtypePubDef")] newtype_pub: remote::NewtypePub,
#[serde(with = "TuplePrivDef")]
tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePrivDef")] tuple_priv: remote::TuplePriv,
#[serde(with = "TuplePubDef")]
tuple_pub: remote::TuplePub,
#[serde(with = "TuplePubDef")] tuple_pub: remote::TuplePub,
#[serde(with = "StructPrivDef")]
struct_priv: remote::StructPriv,
#[serde(with = "StructPrivDef")] struct_priv: remote::StructPriv,
#[serde(with = "StructPubDef")]
struct_pub: remote::StructPub,
#[serde(with = "StructPubDef")] struct_pub: remote::StructPub,
}
#[derive(Serialize, Deserialize)]
@ -121,10 +110,7 @@ struct UnitDef;
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePriv")]
struct PrimitivePrivDef(
#[serde(getter = "remote::PrimitivePriv::get")]
u8
);
struct PrimitivePrivDef(#[serde(getter = "remote::PrimitivePriv::get")] u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::PrimitivePub")]
@ -133,53 +119,41 @@ struct PrimitivePubDef(u8);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePriv")]
struct NewtypePrivDef(
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")]
remote::Unit
#[serde(getter = "remote::NewtypePriv::get", with = "UnitDef")] remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::NewtypePub")]
struct NewtypePubDef(
#[serde(with = "UnitDef")]
remote::Unit
);
struct NewtypePubDef(#[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePriv")]
struct TuplePrivDef(
#[serde(getter = "remote::TuplePriv::first")]
u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")]
remote::Unit
#[serde(getter = "remote::TuplePriv::first")] u8,
#[serde(getter = "remote::TuplePriv::second", with = "UnitDef")] remote::Unit,
);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::TuplePub")]
struct TuplePubDef(
u8,
#[serde(with = "UnitDef")]
remote::Unit
);
struct TuplePubDef(u8, #[serde(with = "UnitDef")] remote::Unit);
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPriv")]
struct StructPrivDef {
#[serde(getter = "remote::StructPriv::a")]
a: u8,
#[serde(getter = "remote::StructPriv::a")] a: u8,
#[serde(getter = "remote::StructPriv::b")]
#[serde(with= "UnitDef")]
#[serde(with = "UnitDef")]
b: remote::Unit,
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "remote::StructPub")]
struct StructPubDef {
#[allow(dead_code)]
a: u8,
#[allow(dead_code)] a: u8,
#[allow(dead_code)]
#[serde(with= "UnitDef")]
#[serde(with = "UnitDef")]
b: remote::Unit,
}

View File

@ -7,7 +7,7 @@
// except according to those terms.
extern crate serde_test;
use self::serde_test::{Token, assert_tokens_readable};
use self::serde_test::{assert_tokens, Configure, Token};
use std::net;
@ -17,9 +17,8 @@ mod macros;
#[test]
fn ip_addr_roundtrip() {
assert_tokens_readable(
&net::IpAddr::from(*b"1234"),
assert_tokens(
&net::IpAddr::from(*b"1234").compact(),
&seq![
Token::NewtypeVariant { name: "IpAddr", variant: "V4" },
@ -27,15 +26,13 @@ fn ip_addr_roundtrip() {
seq b"1234".iter().map(|&b| Token::U8(b)),
Token::TupleEnd,
],
Some(false),
);
}
#[test]
fn socked_addr_roundtrip() {
assert_tokens_readable(
&net::SocketAddr::from((*b"1234567890123456", 1234)),
assert_tokens(
&net::SocketAddr::from((*b"1234567890123456", 1234)).compact(),
&seq![
Token::NewtypeVariant { name: "SocketAddr", variant: "V6" },
@ -48,6 +45,5 @@ fn socked_addr_roundtrip() {
Token::U16(1234),
Token::TupleEnd,
],
Some(false),
);
}

View File

@ -21,11 +21,8 @@ use std::num::Wrapping;
#[cfg(unix)]
use std::str;
extern crate serde;
extern crate serde_test;
use self::serde_test::{Token, assert_ser_tokens, assert_ser_tokens_error,
assert_ser_tokens_readable};
use self::serde_test::{assert_ser_tokens, assert_ser_tokens_error, Configure, Token};
extern crate fnv;
use self::fnv::FnvHasher;
@ -54,28 +51,24 @@ enum Enum {
One(i32),
Seq(i32, i32),
Map { a: i32, b: i32 },
#[serde(skip_serializing)]
SkippedUnit,
#[serde(skip_serializing)]
SkippedOne(i32),
#[serde(skip_serializing)]
SkippedSeq(i32, i32),
#[serde(skip_serializing)]
SkippedMap { _a: i32, _b: i32 },
#[serde(skip_serializing)] SkippedUnit,
#[serde(skip_serializing)] SkippedOne(i32),
#[serde(skip_serializing)] SkippedSeq(i32, i32),
#[serde(skip_serializing)] SkippedMap { _a: i32, _b: i32 },
}
//////////////////////////////////////////////////////////////////////////
macro_rules! declare_tests {
(
readable: $readable:tt
$readable:tt
$($name:ident { $($value:expr => $tokens:expr,)+ })+
) => {
$(
#[test]
fn $name() {
$(
assert_ser_tokens_readable(&$value, $tokens, Some($readable));
assert_ser_tokens(&$value.$readable(), $tokens);
)+
}
)+
@ -408,7 +401,8 @@ declare_tests! {
}
declare_tests! {
readable: true
readable
test_net_ipv4addr_readable {
"1.2.3.4".parse::<net::Ipv4Addr>().unwrap() => &[Token::Str("1.2.3.4")],
}
@ -426,7 +420,8 @@ declare_tests! {
}
declare_tests! {
readable: false
compact
test_net_ipv4addr_compact {
net::Ipv4Addr::from(*b"1234") => &seq![
Token::Tuple { len: 4 },
@ -524,11 +519,7 @@ fn test_cannot_serialize_paths() {
let mut path_buf = PathBuf::new();
path_buf.push(path);
assert_ser_tokens_error(
&path_buf,
&[],
"path contains invalid UTF-8 characters",
);
assert_ser_tokens_error(&path_buf, &[], "path contains invalid UTF-8 characters");
}
#[test]