Bug 1396821 - [WIP] Additional changes to actions. draft
authorHenrik Skupin <mail@hskupin.info>
Sat, 03 Mar 2018 23:20:27 +0100
changeset 770829 1afd8bca10268c17df935613ff2f02df993a011a
parent 770246 7f43e89dd2151ce1ffb6de599c2bf9d9a49f7fa0
push id103511
push userbmo:hskupin@gmail.com
push dateWed, 21 Mar 2018 21:36:26 +0000
bugs1396821
milestone61.0a1
Bug 1396821 - [WIP] Additional changes to actions. MozReview-Commit-ID: JULyofAn5qG
testing/webdriver/src/actions.rs
--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,65 +1,20 @@
 use common::WebElement;
 use serde::{Deserialize, Deserializer};
+use serde::ser::{Serialize, Serializer};
 use serde_json::{Value, Map};
 use std::default::Default;
 
-#[derive(Debug, PartialEq, Serialize)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
 pub struct ActionSequence {
     pub id: Option<String>,
     pub actions: ActionsType
 }
 
-impl<'de> Deserialize<'de> for ActionSequence {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-        where D: Deserializer<'de>
-    {
-        #[derive(Deserialize)]
-        #[serde(tag = "type", rename_all = "lowercase")]
-        enum Helper {
-            Null {
-                id: Option<String>,
-                actions: Vec<NullActionItem>,
-            },
-            Key {
-                id: Option<String>,
-                actions: Vec<KeyActionItem>,
-            },
-            Pointer {
-                id: Option<String>,
-                #[serde(default)]
-                parameters: PointerActionParameters,
-                actions: Vec<PointerActionItem>,
-            },
-        }
-
-        match Helper::deserialize(deserializer)? {
-            Helper::Null { id, actions } => {
-                Ok(ActionSequence {
-                    id: id,
-                    actions: ActionsType::Null{actions},
-                })
-            }
-            Helper::Key { id, actions } => {
-                Ok(ActionSequence {
-                    id: id,
-                    actions: ActionsType::Key{actions},
-                })
-            }
-            Helper::Pointer { id, parameters, actions } => {
-                Ok(ActionSequence {
-                    id: id,
-                    actions: ActionsType::Pointer{parameters, actions},
-                })
-            }
-        }
-    }
-}
-
 impl<'a> From<&'a ActionSequence> for Value {
     fn from(params: &'a ActionSequence) -> Value {
         let mut data: Map<String, Value> = Map::new();
         data.insert("id".into(), params.id.clone().map(|x| x.into()).unwrap_or(Value::Null));
         let (action_type, actions) = match params.actions {
             ActionsType::Null {ref actions} => {
                 ("none",
                  actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
@@ -75,17 +30,18 @@ impl<'a> From<&'a ActionSequence> for Va
             }
         };
         data.insert("type".into(), action_type.into());
         data.insert("actions".into(), actions.into());
         Value::Object(data)
     }
 }
 
-#[derive(Debug, PartialEq, Serialize)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged, rename_all = "lowercase")]
 pub enum ActionsType {
     Null {actions: Vec<NullActionItem>},
     Key {actions: Vec<KeyActionItem>},
     Pointer {parameters: PointerActionParameters, actions:Vec<PointerActionItem>}
 }
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
 #[serde(rename_all="lowercase")]
@@ -168,17 +124,17 @@ impl<'a> From<&'a PointerActionItem> for
         match *params {
             PointerActionItem::General(ref x) => x.into(),
             PointerActionItem::Pointer(ref x) => x.into()
         }
     }
 }
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
-#[serde(tag = "type")]
+#[serde(tag = "type", rename_all="lowercase")]
 pub enum GeneralAction {
     Pause(PauseAction)
 }
 
 impl<'a> From<&'a GeneralAction> for Value {
     fn from(params: &'a GeneralAction) -> Value {
         match *params {
             GeneralAction::Pause(ref x) => x.into()
@@ -248,23 +204,40 @@ impl<'a> From<&'a KeyDownAction> for Val
                     "keyDown".into());
         data.insert("value".to_owned(),
                     params.value.to_string().into());
         Value::Object(data)
     }
 }
 
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
-#[serde(untagged, rename_all="lowercase")]
 pub enum PointerOrigin {
+    #[serde(rename = "viewport")]
     Viewport,
+    #[serde(rename = "pointer")]
     Pointer,
+    #[serde(
+        rename = "element-6066-11e4-a52e-4f735466cecf",
+        serialize_with = "serialize_webelement_id",
+        deserialize_with = "deserialize_webelement_id")]
     Element(WebElement),
 }
 
+fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
+    where S: Serializer
+{
+    element.id.serialize(serializer)
+}
+
+fn deserialize_webelement_id<'de, D>(deserializer: D) -> Result<WebElement, D::Error>
+    where D: Deserializer<'de>
+{
+    String::deserialize(deserializer).map(|id| WebElement { id })
+}
+
 impl<'a> From<&'a PointerOrigin> for Value {
     fn from(params: &'a PointerOrigin) -> Value {
         match *params {
             PointerOrigin::Viewport => "viewport".into(),
             PointerOrigin::Pointer => "pointer".into(),
             PointerOrigin::Element(ref x) => x.into(),
         }
     }
@@ -342,104 +315,512 @@ pub struct PointerMoveAction {
     pub x: Option<i64>,
     pub y: Option<i64>
 }
 
 impl<'a> From<&'a PointerMoveAction> for Value {
     fn from(params: &'a PointerMoveAction) -> Value {
         let mut data = Map::new();
         data.insert("type".to_owned(), "pointerMove".into());
+        data.insert("origin".to_owned(), (&params.origin).into());
+
         if let Some(duration) = params.duration {
             data.insert("duration".to_owned(),
                         duration.into());
         }
-
-        data.insert("origin".to_owned(), (&params.origin).into());
-
         if let Some(x) = params.x {
             data.insert("x".to_owned(), x.into());
         }
         if let Some(y) = params.y {
             data.insert("y".to_owned(), y.into());
         }
         Value::Object(data)
     }
 }
 
 #[cfg(test)]
 mod test {
     use serde_json;
-    use command::ActionsParameters;
-    use common::WebElement;
     use super::*;
 
     #[test]
-    fn test_pointer_no_parameters() {
-        let expected = ActionsParameters {
-            actions: vec![
-                ActionSequence {
-                    id: None,
-                    actions: ActionsType::Pointer {
-                        parameters: PointerActionParameters {
-                            pointer_type: PointerType::Mouse
-                        },
-                        actions: vec!{
-                            PointerActionItem::Pointer (
-                                PointerAction::Down (
-                                    PointerDownAction {
-                                        button: 0
-                                    }
-                                )
-                            ),
-                            PointerActionItem::Pointer(
-                                PointerAction::Move (
-                                    PointerMoveAction {
-                                        duration: Some(100),
-                                        x: Some(5),
-                                        y: Some(10),
-                                        origin: PointerOrigin::Pointer
-                                    }
-                                )
-                            ),
-                            PointerActionItem::Pointer(
-                                PointerAction::Move (
-                                    PointerMoveAction {
-                                        duration: Some(200),
-                                        x: Some(10),
-                                        y: Some(20),
-                                        origin: PointerOrigin::Element(
-                                            WebElement {
-                                                id: "elem".into()
-                                            }
-                                        )
-                                    }
-                                )
-                            ),
-                            PointerActionItem::Pointer(
-                                PointerAction::Up (
-                                    PointerUpAction {
-                                        button: 0
-                                    }
-                                )
-                            ),
-                            PointerActionItem::Pointer(
-                                PointerAction::Cancel
-                            ),
-                        }
-                    }
+    fn test_action_sequence_null() {
+        let expected = ActionSequence {
+            id: Some("none".into()),
+            actions: ActionsType::Null {
+                actions: vec!{
+                    NullActionItem::General (
+                        GeneralAction::Pause ( PauseAction { duration: 1 } )
+                    )
+                }
+            }
+        };
+
+        let data = r#"{
+            "id": "none",
+            "actions": {"actions": [{"type": "pause", "duration": 1}]}
+        }"#;
+
+        let actual: ActionSequence = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_action_sequence_key() {
+        let expected = ActionSequence {
+            id: Some("some_key".into()),
+            actions: ActionsType::Key {
+                actions: vec!{
+                    KeyActionItem::Key (
+                        KeyAction::Down ( KeyDownAction { value: String::from("f") } )
+                    )
                 }
-            ]
+            }
+        };
+
+        let data = r#"{
+            "id": "some_key",
+            "actions": {"actions": [{"type": "keyDown", "value": "f"}]}
+        }"#;
+
+        let actual: ActionSequence = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_action_sequence_pointer() {
+        let expected = ActionSequence {
+            id: Some("some_pointer".into()),
+            actions: ActionsType::Pointer {
+                parameters: PointerActionParameters {
+                    pointer_type: PointerType::Mouse
+                },
+                actions: vec!{
+                    PointerActionItem::Pointer (
+                        PointerAction::Down ( PointerDownAction { button: 0 } )
+                    ),
+                    PointerActionItem::Pointer (
+                        PointerAction::Move ( PointerMoveAction {
+                            origin: PointerOrigin::Pointer,
+                            duration: None,
+                            x: Some(10),
+                            y: Some(20),
+                        })
+                    ),
+                    PointerActionItem::Pointer (
+                        PointerAction::Up ( PointerUpAction { button: 0 } )
+                    ),
+                }
+            }
+        };
+
+        let data = r#"{
+            "id": "some_pointer",
+            "actions": {
+                "parameters": {
+                    "pointerType": "mouse"
+                },
+                "actions": [
+                    {"type": "pointerDown", "button": 0},
+                    {"type": "pointerMove", "origin":"pointer", "x": 10, "y": 20},
+                    {"type": "pointerUp", "button": 0}
+                ]
+            }
+        }"#;
+        let actual: ActionSequence = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_actions_type_null() {
+        let expected = ActionsType::Null {
+            actions: vec!{
+                NullActionItem::General (
+                    GeneralAction::Pause ( PauseAction { duration: 1 } )
+                )
+            }
+        };
+
+        let data = r#"{"actions": [{"type": "pause", "duration":1}]}"#;
+        let actual: ActionsType = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_actions_type_key() {
+        let expected = ActionsType::Key {
+            actions: vec!{
+                KeyActionItem::Key (
+                    KeyAction::Down ( KeyDownAction { value: String::from("f") } )
+                )
+            }
+        };
+
+        let data = r#"{"actions": [{"type": "keyDown", "value": "f"}]}"#;
+        let actual: ActionsType = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_actions_type_pointer() {
+        let expected = ActionsType::Pointer {
+            parameters: PointerActionParameters {
+                pointer_type: PointerType::Mouse
+            },
+            actions: vec!{
+                PointerActionItem::Pointer (
+                    PointerAction::Down ( PointerDownAction { button: 1 } )
+                )
+            }
         };
 
         let data = r#"{
-"actions": [
-    {"type": "pointer", "actions": [
-    {"type": "pointerDown", "button": 0},
-    {"type": "pointerMove", "x": 5, "y": 10, "origin": "relative"},
-    {"type": "pointerMove", "x": 5, "y": 10, "origin": {"element-6066-11e4-a52e-4f735466cecf": "elem"}},
-    {"type": "pointerUp", "button": 0},
-    {"type": "pointerCancel"}
-  ]
-}]}"#;
-        let actual: ActionsParameters = serde_json::from_str(&data).unwrap();
+            "parameters": {"pointerType": "mouse"},
+            "actions": [
+                {"type": "pointerDown", "button": 1}
+            ]}"#;
+        let actual: ActionsType = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_null_action_item_general() {
+        let expected = NullActionItem::General ( GeneralAction::Pause (
+            PauseAction { duration: 1 }
+        ));
+
+        let data = r#"{"type": "pause", "duration": 1}"#;
+        let actual: NullActionItem = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_null_action_item_invalid_type() {
+        let data = r#"{"type": "invalid"}"#;
+        assert!(serde_json::from_str::<NullActionItem>(&data).is_err());
+    }
+
+    #[test]
+    fn test_key_action_item_general() {
+        let expected = KeyActionItem::General ( GeneralAction::Pause (
+            PauseAction { duration: 1 }
+        ));
+
+        let data = r#"{"type": "pause", "duration": 1}"#;
+        let actual: KeyActionItem = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_action_item_key() {
+        let expected = KeyActionItem::Key ( KeyAction::Down (
+            KeyDownAction { value: String::from("f") }
+        ));
+
+        let data = r#"{"type": "keyDown", "value": "f"}"#;
+        let actual: KeyActionItem = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_action_item_invalid_type() {
+        let data = r#"{"type": "invalid"}"#;
+        assert!(serde_json::from_str::<KeyActionItem>(&data).is_err());
+    }
+
+    #[test]
+    fn test_key_action_down() {
+        let expected = KeyAction::Down ( KeyDownAction { value: String::from("f") } );
+
+        let data = r#"{"type": "keyDown", "value": "f"}"#;
+        let actual: KeyAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_action_up() {
+        let expected = KeyAction::Up ( KeyUpAction { value: String::from("f") } );
+
+        let data = r#"{"type": "keyUp", "value": "f"}"#;
+        let actual: KeyAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_action_invalid_type() {
+        let data = r#"{"type": "invalid", "value": "f"}"#;
+        assert!(serde_json::from_str::<KeyAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_key_action_missing_type() {
+        let data = r#"{"value": "f"}"#;
+        assert!(serde_json::from_str::<KeyAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_key_down_action() {
+        let expected = KeyDownAction { value: String::from("f") };
+
+        let data = r#"{"type": "keyDown", "value": "f"}"#;
+        let actual: KeyDownAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_down_action_missing_value() {
+        let data = r#"{"type": "keyDown"}"#;
+        assert!(serde_json::from_str::<KeyDownAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_key_up_action() {
+        let expected = KeyUpAction { value: String::from("f") };
+
+        let data = r#"{"type": "keyUp", "value": "f"}"#;
+        let actual: KeyUpAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_key_up_action_missing_value() {
+        let data = r#"{"type": "keyDown"}"#;
+        assert!(serde_json::from_str::<KeyUpAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_action_item_general() {
+        let expected = PointerActionItem::General ( GeneralAction::Pause (
+            PauseAction { duration: 1 }
+        ));
+
+        let data = r#"{"type": "pause", "duration": 1}"#;
+        let actual: PointerActionItem = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_item_pointer() {
+        let expected = PointerActionItem::Pointer ( PointerAction::Cancel );
+
+        let data = r#"{"type": "pointerCancel"}"#;
+        let actual: PointerActionItem = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_item_invalid_type() {
+        let data = r#"{"type": "pointerInvalid"}"#;
+        assert!(serde_json::from_str::<PointerActionItem>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_action_parameters() {
+        let expected = PointerActionParameters { pointer_type: PointerType::Mouse};
+
+        let data = r#"{"pointerType": "mouse"}"#;
+        let actual: PointerActionParameters = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_general_action_pause() {
+        let expected = GeneralAction::Pause ( PauseAction { duration: 1 } );
+
+        let data = r#"{"type": "pause", "duration": 1}"#;
+        let actual: GeneralAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pause_action() {
+        let expected = PauseAction { duration: 1 };
+
+        let data = r#"{"duration": 1}"#;
+        let actual: PauseAction = serde_json::from_str(&data).unwrap();
         assert_eq!(expected, actual);
     }
+
+    #[test]
+    fn test_pause_action_missing_duration() {
+        let data = r#"{}"#;
+        assert!(serde_json::from_str::<PauseAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_action_cancel() {
+        let expected = PointerAction::Cancel;
+
+        let data = r#"{"type": "pointerCancel"}"#;
+        let actual: PointerAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_down() {
+        let expected = PointerAction::Down ( PointerDownAction { button: 1} );
+
+        let data = r#"{"type": "pointerDown", "button": 1}"#;
+        let actual: PointerAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_up() {
+        let expected = PointerAction::Up ( PointerUpAction { button: 1} );
+
+        let data = r#"{"type": "pointerUp", "button": 1}"#;
+        let actual: PointerAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_move() {
+        let expected = PointerAction::Move ( PointerMoveAction {
+            duration:  None,
+            origin: PointerOrigin::Pointer,
+            x: None,
+            y: None,
+        });
+
+        let data = r#"{"type": "pointerMove", "origin": "pointer"}"#;
+        let actual: PointerAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_action_invaid_type() {
+        let data = r#"{"type": "pointerInvald"}"#;
+        assert!(serde_json::from_str::<PointerAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_action_missing_type() {
+        let data = r#"{"button": 1}"#;
+        assert!(serde_json::from_str::<PointerAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_down_action() {
+        let expected = PointerDownAction { button: 1 };
+
+        let data = r#"{"button": 1}"#;
+        let actual: PointerDownAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_down_action_invalid_field() {
+        let data = r#"{"duration": 100}"#;
+        assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_down_action_missing_button_field() {
+        let data = r#"{}"#;
+        assert!(serde_json::from_str::<PointerDownAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_up_action() {
+        let expected = PointerUpAction { button: 1 };
+
+        let data = r#"{"button": 1}"#;
+        let actual: PointerUpAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_up_action_invalid_field() {
+        let data = r#"{"duration": 100}"#;
+        assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_up_action_missing_button_field() {
+        let data = r#"{}"#;
+        assert!(serde_json::from_str::<PointerUpAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_move_action() {
+        let expected = PointerMoveAction {
+            duration: Some(100),
+            origin: PointerOrigin::Pointer,
+            x: Some(5),
+            y: Some(10),
+        };
+
+        let data = r#"{"duration": 100, "origin": "pointer", "x": 5, "y": 10}"#;
+        let actual: PointerMoveAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_move_action_missing_origin_field() {
+        let data = r#"{"duration": 100, "x": 5, "y": 10}"#;
+        assert!(serde_json::from_str::<PointerMoveAction>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_move_action_missing_optional_fields() {
+        let expected = PointerMoveAction {
+            duration: None,
+            origin: PointerOrigin::Pointer,
+            x: None,
+            y: None,
+        };
+
+        let data = r#"{"origin": "pointer"}"#;
+        let actual: PointerMoveAction = serde_json::from_str(&data).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_origin() {
+        // TODO: Fix with maybe custom serialize / deserialze method
+        // similar like https://github.com/serde-rs/serde/issues/751#issuecomment-277580700
+        let data = r#"{"element-6066-11e4-a52e-4f735466cecf":"elem"}"#;
+        let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
+        let expected = PointerOrigin::Element(WebElement { id: "elem".into() });
+        assert_eq!(expected, actual);
+
+        let data = r#""pointer""#;
+        let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
+        let expected = PointerOrigin::Pointer;
+        assert_eq!(expected, actual);
+
+        let data = r#""viewport""#;
+        let actual: PointerOrigin = serde_json::from_str(&data).unwrap();
+        let expected = PointerOrigin::Viewport;
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_origin_invalid_type() {
+        let data = r#""invalid""#;
+        assert!(serde_json::from_str::<PointerOrigin>(&data).is_err());
+    }
+
+    #[test]
+    fn test_pointer_type() {
+        let data = r#""mouse""#;
+        let actual: PointerType = serde_json::from_str(&data).unwrap();
+        let expected = PointerType::Mouse;
+        assert_eq!(expected, actual);
+
+        let data = r#""pen""#;
+        let actual: PointerType = serde_json::from_str(&data).unwrap();
+        let expected = PointerType::Pen;
+        assert_eq!(expected, actual);
+
+        let data = r#""touch""#;
+        let actual: PointerType = serde_json::from_str(&data).unwrap();
+        let expected = PointerType::Touch;
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn test_pointer_type_invalid_type() {
+        let data = r#""invalid""#;
+        assert!(serde_json::from_str::<PointerType>(&data).is_err());
+    }
 }