Repository: ron-rs/ron
Pull request #166 (2019-05-26 11:13:12)

#123: add tests for different enum representations
This pull request is addressing issue #123.

Currently it only adds tests mentioned in the issue.
I'm not sure where to put the documentation, so would appreciate some guiding.

If anything needs to be changed, please say it. This is my first PR.


Patch:
diff --git a/src/de/id.rs b/src/de/id.rs
index 1ae1d485..bfd526f6 100644
--- a/src/de/id.rs
+++ b/src/de/id.rs
@@ -22,6 +22,13 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
         self.d.deserialize_identifier(visitor)
     }
 
+    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.deserialize_identifier(visitor)
+    }
+
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: Visitor<'b>,
@@ -113,13 +120,6 @@ impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> {
         unimplemented!("IdDeserializer may only be used for identifiers")
     }
 
-    fn deserialize_str<V>(self, _: V) -> Result<V::Value>
-    where
-        V: Visitor<'b>,
-    {
-        unimplemented!("IdDeserializer may only be used for identifiers")
-    }
-
     fn deserialize_string<V>(self, _: V) -> Result<V::Value>
     where
         V: Visitor<'b>,
diff --git a/src/de/mod.rs b/src/de/mod.rs
index cd4ad3cc..e80f17bb 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -6,10 +6,12 @@ use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
 use std::{borrow::Cow, io, str};
 
 use self::id::IdDeserializer;
+use self::tag::TagDeserializer;
 use crate::parse::{AnyNum, Bytes, Extensions, ParsedStr};
 
 mod error;
 mod id;
+mod tag;
 #[cfg(test)]
 mod tests;
 mod value;
@@ -577,7 +579,7 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
         if self.de.bytes.consume(":") {
             self.de.bytes.skip_ws()?;
 
-            let res = seed.deserialize(&mut *self.de)?;
+            let res = seed.deserialize(&mut TagDeserializer::new(&mut *self.de))?;
 
             self.had_comma = self.de.bytes.comma()?;
 
diff --git a/src/de/tag.rs b/src/de/tag.rs
new file mode 100644
index 00000000..613e390d
--- /dev/null
+++ b/src/de/tag.rs
@@ -0,0 +1,230 @@
+use serde::de::{self, Visitor};
+
+use super::{Deserializer, Error, Result};
+
+pub struct TagDeserializer<'a, 'b: 'a> {
+    d: &'a mut Deserializer<'b>,
+}
+
+impl<'a, 'b: 'a> TagDeserializer<'a, 'b> {
+    pub fn new(d: &'a mut Deserializer<'b>) -> Self {
+        TagDeserializer { d }
+    }
+}
+
+impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut TagDeserializer<'a, 'b> {
+    type Error = Error;
+
+    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_str(visitor)
+    }
+
+    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.deserialize_str(visitor)
+    }
+
+    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_any(visitor)
+    }
+
+    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_bool(visitor)
+    }
+
+    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_i8(visitor)
+    }
+
+    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_i16(visitor)
+    }
+
+    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_i32(visitor)
+    }
+
+    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_i64(visitor)
+    }
+
+    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_u8(visitor)
+    }
+
+    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_u16(visitor)
+    }
+
+    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_u32(visitor)
+    }
+
+    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_u64(visitor)
+    }
+
+    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_f32(visitor)
+    }
+
+    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_f64(visitor)
+    }
+
+    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_char(visitor)
+    }
+
+    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_string(visitor)
+    }
+
+    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_bytes(visitor)
+    }
+
+    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_byte_buf(visitor)
+    }
+
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_option(visitor)
+    }
+
+    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_unit(visitor)
+    }
+
+    fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_unit_struct(name, visitor)
+    }
+
+    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_newtype_struct(name, visitor)
+    }
+
+    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_seq(visitor)
+    }
+
+    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_tuple(len, visitor)
+    }
+
+    fn deserialize_tuple_struct<V>(self, name: &'static str, len: usize, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_tuple_struct(name, len, visitor)
+    }
+
+    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_map(visitor)
+    }
+
+    fn deserialize_struct<V>(
+        self,
+        name: &'static str,
+        fields: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_struct(name, fields, visitor)
+    }
+
+    fn deserialize_enum<V>(
+        self,
+        name: &'static str,
+        variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_enum(name, variants, visitor)
+    }
+
+    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
+        where
+            V: Visitor<'b>,
+    {
+        self.d.deserialize_ignored_any(visitor)
+    }
+}


Test patch:
diff --git a/tests/123_enum_representation.rs b/tests/123_enum_representation.rs
new file mode 100644
index 00000000..19504bfe
--- /dev/null
+++ b/tests/123_enum_representation.rs
@@ -0,0 +1,300 @@
+use std::fmt::Debug;
+use std::cmp::PartialEq;
+use serde::{Serialize, Deserialize};
+use ron::ser::to_string;
+use ron::de::from_str;
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+enum Inner {
+    Foo,
+    Bar,
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+enum EnumStructExternally {
+    VariantA { foo: u32, bar: u32, different: u32 },
+    VariantB { foo: u32, bar: u32 },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(tag = "type")]
+enum EnumStructInternally {
+    VariantA { foo: u32, bar: u32, different: u32 },
+    VariantB { foo: u32, bar: u32 },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(tag = "type", content = "content")]
+enum EnumStructAdjacently {
+    VariantA { foo: u32, bar: u32, different: Inner },
+    VariantB { foo: u32, bar: u32 },
+}
+
+#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
+#[serde(untagged)]
+enum EnumStructUntagged {
+    VariantA { foo: u32, bar: u32, different: u32 },
+    VariantB { foo: u32, bar: u32 },
+}
+
+fn test_ser<T: Serialize>(value: &T, expected: &str) {
+    let actual = to_string(value).expect("Failed to serialize");
+    assert_eq!(actual, expected);
+}
+
+fn test_de<T>(s: &str, expected: T)
+    where T: for<'a> Deserialize<'a> + Debug + PartialEq {
+    let actual: Result<T, _> = from_str(s);
+    assert_eq!(actual, Ok(expected));
+}
+
+fn test_roundtrip<T>(value: T)
+    where T: Serialize + for<'a> Deserialize<'a> + Debug + PartialEq {
+    let s = to_string(&value).expect("Failed to serialize");
+    let actual: Result<T, _> = from_str(&s);
+    assert_eq!(actual, Ok(value));
+}
+
+#[test]
+fn test_externally_a_ser() {
+    let v = EnumStructExternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    let e = "VariantA(foo:1,bar:2,different:3,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_externally_b_ser() {
+    let v = EnumStructExternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    let e = "VariantB(foo:1,bar:2,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_internally_a_ser() {
+    let v = EnumStructInternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    let e = "(type:\"VariantA\",foo:1,bar:2,different:3,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_internally_b_ser() {
+    let v = EnumStructInternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    let e = "(type:\"VariantB\",foo:1,bar:2,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_adjacently_a_ser() {
+    let v = EnumStructAdjacently::VariantA {
+        foo: 1,
+        bar: 2,
+        different: Inner::Foo,
+    };
+    let e = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo,),)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_adjacently_b_ser() {
+    let v = EnumStructAdjacently::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    let e = "(type:\"VariantB\",content:(foo:1,bar:2,),)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_untagged_a_ser() {
+    let v = EnumStructUntagged::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    let e = "(foo:1,bar:2,different:3,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_untagged_b_ser() {
+    let v = EnumStructUntagged::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    let e = "(foo:1,bar:2,)";
+    test_ser(&v, e);
+}
+
+#[test]
+fn test_externally_a_de() {
+    let s = "VariantA(foo:1,bar:2,different:3,)";
+    let e = EnumStructExternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_externally_b_de() {
+    let s = "VariantB(foo:1,bar:2,)";
+    let e = EnumStructExternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_internally_a_de() {
+    let s = "(type:\"VariantA\",foo:1,bar:2,different:3,)";
+    let e = EnumStructInternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_internally_b_de() {
+    let s = "(type:\"VariantB\",foo:1,bar:2,)";
+    let e = EnumStructInternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_adjacently_a_de() {
+    let s = "(type:\"VariantA\",content:(foo:1,bar:2,different:Foo,),)";
+    let e = EnumStructAdjacently::VariantA {
+        foo: 1,
+        bar: 2,
+        different: Inner::Foo,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_adjacently_b_de() {
+    let s = "(type:\"VariantB\",content:(foo:1,bar:2,),)";
+    let e = EnumStructAdjacently::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_untagged_a_de() {
+    let s = "(foo:1,bar:2,different:3,)";
+    let e = EnumStructUntagged::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_untagged_b_de() {
+    let s = "(foo:1,bar:2,)";
+    let e = EnumStructUntagged::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_de(s, e);
+}
+
+#[test]
+fn test_externally_a_roundtrip() {
+    let v = EnumStructExternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_externally_b_roundtrip() {
+    let v = EnumStructExternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_internally_a_roundtrip() {
+    let v = EnumStructInternally::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_internally_b_roundtrip() {
+    let v = EnumStructInternally::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_adjacently_a_roundtrip() {
+    let v = EnumStructAdjacently::VariantA {
+        foo: 1,
+        bar: 2,
+        different: Inner::Foo,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_adjacently_b_roundtrip() {
+    let v = EnumStructAdjacently::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_untagged_a_roundtrip() {
+    let v = EnumStructUntagged::VariantA {
+        foo: 1,
+        bar: 2,
+        different: 3,
+    };
+    test_roundtrip(v);
+}
+
+#[test]
+fn test_untagged_b_roundtrip() {
+    let v = EnumStructUntagged::VariantB {
+        foo: 1,
+        bar: 2,
+    };
+    test_roundtrip(v);
+}