1 use serde::ser::{Serialize, Serializer};
2 use serde::{Deserialize, Deserializer};
3 use std::collections::HashMap;
4 
5 pub static ELEMENT_KEY: &str = "element-6066-11e4-a52e-4f735466cecf";
6 pub static FRAME_KEY: &str = "frame-075b-4da1-b6ba-e579c2d3230a";
7 pub static WINDOW_KEY: &str = "window-fcc6-11e5-b4f8-330a88ab9d7f";
8 
9 pub static MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
10 
11 pub type Parameters = HashMap<String, String>;
12 
13 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
14 pub struct Cookie {
15     pub name: String,
16     pub value: String,
17     pub path: Option<String>,
18     pub domain: Option<String>,
19     #[serde(default)]
20     pub secure: bool,
21     #[serde(rename = "httpOnly")]
22     pub http_only: bool,
23     #[serde(skip_serializing_if = "Option::is_none")]
24     pub expiry: Option<Date>,
25 }
26 
27 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
28 pub struct Date(pub u64);
29 
30 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
31 #[serde(untagged)]
32 pub enum FrameId {
33     Short(u16),
34     #[serde(
35         rename = "element-6066-11e4-a52e-4f735466cecf",
36         serialize_with = "serialize_webelement_id"
37     )]
38     Element(WebElement),
39 }
40 
41 // TODO(Henrik): Remove when ToMarionette trait has been fixed (Bug 1481776)
serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,42 fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
43 where
44     S: Serializer,
45 {
46     element.serialize(serializer)
47 }
48 
49 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
50 pub enum LocatorStrategy {
51     #[serde(rename = "css selector")]
52     CSSSelector,
53     #[serde(rename = "link text")]
54     LinkText,
55     #[serde(rename = "partial link text")]
56     PartialLinkText,
57     #[serde(rename = "tag name")]
58     TagName,
59     #[serde(rename = "xpath")]
60     XPath,
61 }
62 
63 #[derive(Clone, Debug, PartialEq)]
64 pub struct WebElement(pub String);
65 
66 // private
67 #[derive(Serialize, Deserialize)]
68 struct WebElementObject {
69     #[serde(rename = "element-6066-11e4-a52e-4f735466cecf")]
70     id: String,
71 }
72 
73 impl Serialize for WebElement {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,74     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75     where
76         S: Serializer,
77     {
78         WebElementObject { id: self.0.clone() }.serialize(serializer)
79     }
80 }
81 
82 impl<'de> Deserialize<'de> for WebElement {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,83     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84     where
85         D: Deserializer<'de>,
86     {
87         Deserialize::deserialize(deserializer).map(|WebElementObject { id }| WebElement(id))
88     }
89 }
90 
91 impl WebElement {
to_string(&self) -> String92     pub fn to_string(&self) -> String {
93         self.0.clone()
94     }
95 }
96 
97 #[derive(Clone, Debug, PartialEq)]
98 pub struct WebFrame(pub String);
99 
100 // private
101 #[derive(Serialize, Deserialize)]
102 struct WebFrameObject {
103     #[serde(rename = "frame-075b-4da1-b6ba-e579c2d3230a")]
104     id: String,
105 }
106 
107 impl Serialize for WebFrame {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,108     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109     where
110         S: Serializer,
111     {
112         WebFrameObject { id: self.0.clone() }.serialize(serializer)
113     }
114 }
115 
116 impl<'de> Deserialize<'de> for WebFrame {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,117     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
118     where
119         D: Deserializer<'de>,
120     {
121         Deserialize::deserialize(deserializer).map(|WebFrameObject { id }| WebFrame(id))
122     }
123 }
124 
125 #[derive(Clone, Debug, PartialEq)]
126 pub struct WebWindow(pub String);
127 
128 // private
129 #[derive(Serialize, Deserialize)]
130 struct WebWindowObject {
131     #[serde(rename = "window-fcc6-11e5-b4f8-330a88ab9d7f")]
132     id: String,
133 }
134 
135 impl Serialize for WebWindow {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,136     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
137     where
138         S: Serializer,
139     {
140         WebWindowObject { id: self.0.clone() }.serialize(serializer)
141     }
142 }
143 
144 impl<'de> Deserialize<'de> for WebWindow {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,145     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
146     where
147         D: Deserializer<'de>,
148     {
149         Deserialize::deserialize(deserializer).map(|WebWindowObject { id }| WebWindow(id))
150     }
151 }
152 
153 #[cfg(test)]
154 mod tests {
155     use super::*;
156     use crate::test::{assert_ser, assert_ser_de};
157     use serde_json::{self, json};
158 
159     #[test]
test_json_date()160     fn test_json_date() {
161         assert_ser_de(&Date(1234), json!(1234));
162     }
163 
164     #[test]
test_json_date_invalid()165     fn test_json_date_invalid() {
166         assert!(serde_json::from_value::<Date>(json!("2018-01-01")).is_err());
167     }
168 
169     #[test]
test_json_frame_id_short()170     fn test_json_frame_id_short() {
171         assert_ser_de(&FrameId::Short(1234), json!(1234));
172     }
173 
174     #[test]
test_json_frame_id_webelement()175     fn test_json_frame_id_webelement() {
176         assert_ser(
177             &FrameId::Element(WebElement("elem".into())),
178             json!({ELEMENT_KEY: "elem"}),
179         );
180     }
181 
182     #[test]
test_json_frame_id_invalid()183     fn test_json_frame_id_invalid() {
184         assert!(serde_json::from_value::<FrameId>(json!(true)).is_err());
185     }
186 
187     #[test]
test_json_locator_strategy_css_selector()188     fn test_json_locator_strategy_css_selector() {
189         assert_ser_de(&LocatorStrategy::CSSSelector, json!("css selector"));
190     }
191 
192     #[test]
test_json_locator_strategy_link_text()193     fn test_json_locator_strategy_link_text() {
194         assert_ser_de(&LocatorStrategy::LinkText, json!("link text"));
195     }
196 
197     #[test]
test_json_locator_strategy_partial_link_text()198     fn test_json_locator_strategy_partial_link_text() {
199         assert_ser_de(
200             &LocatorStrategy::PartialLinkText,
201             json!("partial link text"),
202         );
203     }
204 
205     #[test]
test_json_locator_strategy_tag_name()206     fn test_json_locator_strategy_tag_name() {
207         assert_ser_de(&LocatorStrategy::TagName, json!("tag name"));
208     }
209 
210     #[test]
test_json_locator_strategy_xpath()211     fn test_json_locator_strategy_xpath() {
212         assert_ser_de(&LocatorStrategy::XPath, json!("xpath"));
213     }
214 
215     #[test]
test_json_locator_strategy_invalid()216     fn test_json_locator_strategy_invalid() {
217         assert!(serde_json::from_value::<LocatorStrategy>(json!("foo")).is_err());
218     }
219 
220     #[test]
test_json_webelement()221     fn test_json_webelement() {
222         assert_ser_de(&WebElement("elem".into()), json!({ELEMENT_KEY: "elem"}));
223     }
224 
225     #[test]
test_json_webelement_invalid()226     fn test_json_webelement_invalid() {
227         assert!(serde_json::from_value::<WebElement>(json!({"invalid": "elem"})).is_err());
228     }
229 
230     #[test]
test_json_webframe()231     fn test_json_webframe() {
232         assert_ser_de(&WebFrame("frame".into()), json!({FRAME_KEY: "frame"}));
233     }
234 
235     #[test]
test_json_webframe_invalid()236     fn test_json_webframe_invalid() {
237         assert!(serde_json::from_value::<WebFrame>(json!({"invalid": "frame"})).is_err());
238     }
239 
240     #[test]
test_json_webwindow()241     fn test_json_webwindow() {
242         assert_ser_de(&WebWindow("window".into()), json!({WINDOW_KEY: "window"}));
243     }
244 
245     #[test]
test_json_webwindow_invalid()246     fn test_json_webwindow_invalid() {
247         assert!(serde_json::from_value::<WebWindow>(json!({"invalid": "window"})).is_err());
248     }
249 }
250