1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use serde::ser::{Serialize, Serializer};
6 use serde::{Deserialize, Deserializer};
7 use std::collections::HashMap;
8 use std::fmt::{self, Display, Formatter};
9 
10 pub static ELEMENT_KEY: &str = "element-6066-11e4-a52e-4f735466cecf";
11 pub static FRAME_KEY: &str = "frame-075b-4da1-b6ba-e579c2d3230a";
12 pub static SHADOW_KEY: &str = "shadow-6066-11e4-a52e-4f735466cecf";
13 pub static WINDOW_KEY: &str = "window-fcc6-11e5-b4f8-330a88ab9d7f";
14 
15 pub static MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
16 
17 pub type Parameters = HashMap<String, String>;
18 
19 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
20 pub struct Cookie {
21     pub name: String,
22     pub value: String,
23     pub path: Option<String>,
24     pub domain: Option<String>,
25     #[serde(default)]
26     pub secure: bool,
27     #[serde(rename = "httpOnly")]
28     pub http_only: bool,
29     #[serde(skip_serializing_if = "Option::is_none")]
30     pub expiry: Option<Date>,
31     #[serde(skip_serializing_if = "Option::is_none", rename = "sameSite")]
32     pub same_site: Option<String>,
33 }
34 
35 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
36 pub struct Date(pub u64);
37 
38 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
39 #[serde(untagged)]
40 pub enum FrameId {
41     Short(u16),
42     #[serde(
43         rename = "element-6066-11e4-a52e-4f735466cecf",
44         serialize_with = "serialize_webelement_id"
45     )]
46     Element(WebElement),
47 }
48 
49 // 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,50 fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
51 where
52     S: Serializer,
53 {
54     element.serialize(serializer)
55 }
56 
57 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
58 pub enum LocatorStrategy {
59     #[serde(rename = "css selector")]
60     CSSSelector,
61     #[serde(rename = "link text")]
62     LinkText,
63     #[serde(rename = "partial link text")]
64     PartialLinkText,
65     #[serde(rename = "tag name")]
66     TagName,
67     #[serde(rename = "xpath")]
68     XPath,
69 }
70 
71 #[derive(Clone, Debug, PartialEq)]
72 pub struct ShadowRoot(pub String);
73 
74 // private
75 #[derive(Serialize, Deserialize)]
76 struct ShadowRootObject {
77     #[serde(rename = "shadow-6066-11e4-a52e-4f735466cecf")]
78     id: String,
79 }
80 
81 impl Serialize for ShadowRoot {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,82     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83     where
84         S: Serializer,
85     {
86         ShadowRootObject { id: self.0.clone() }.serialize(serializer)
87     }
88 }
89 
90 impl<'de> Deserialize<'de> for ShadowRoot {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,91     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92     where
93         D: Deserializer<'de>,
94     {
95         Deserialize::deserialize(deserializer).map(|ShadowRootObject { id }| ShadowRoot(id))
96     }
97 }
98 
99 impl Display for ShadowRoot {
fmt(&self, f: &mut Formatter) -> fmt::Result100     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
101         write!(f, "{}", self.0)
102     }
103 }
104 
105 #[derive(Clone, Debug, PartialEq)]
106 pub struct WebElement(pub String);
107 
108 // private
109 #[derive(Serialize, Deserialize)]
110 struct WebElementObject {
111     #[serde(rename = "element-6066-11e4-a52e-4f735466cecf")]
112     id: String,
113 }
114 
115 impl Serialize for WebElement {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,116     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117     where
118         S: Serializer,
119     {
120         WebElementObject { id: self.0.clone() }.serialize(serializer)
121     }
122 }
123 
124 impl<'de> Deserialize<'de> for WebElement {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,125     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126     where
127         D: Deserializer<'de>,
128     {
129         Deserialize::deserialize(deserializer).map(|WebElementObject { id }| WebElement(id))
130     }
131 }
132 
133 impl Display for WebElement {
fmt(&self, f: &mut Formatter) -> fmt::Result134     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
135         write!(f, "{}", self.0)
136     }
137 }
138 
139 #[derive(Clone, Debug, PartialEq)]
140 pub struct WebFrame(pub String);
141 
142 // private
143 #[derive(Serialize, Deserialize)]
144 struct WebFrameObject {
145     #[serde(rename = "frame-075b-4da1-b6ba-e579c2d3230a")]
146     id: String,
147 }
148 
149 impl Serialize for WebFrame {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,150     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151     where
152         S: Serializer,
153     {
154         WebFrameObject { id: self.0.clone() }.serialize(serializer)
155     }
156 }
157 
158 impl<'de> Deserialize<'de> for WebFrame {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,159     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160     where
161         D: Deserializer<'de>,
162     {
163         Deserialize::deserialize(deserializer).map(|WebFrameObject { id }| WebFrame(id))
164     }
165 }
166 
167 #[derive(Clone, Debug, PartialEq)]
168 pub struct WebWindow(pub String);
169 
170 // private
171 #[derive(Serialize, Deserialize)]
172 struct WebWindowObject {
173     #[serde(rename = "window-fcc6-11e5-b4f8-330a88ab9d7f")]
174     id: String,
175 }
176 
177 impl Serialize for WebWindow {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,178     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
179     where
180         S: Serializer,
181     {
182         WebWindowObject { id: self.0.clone() }.serialize(serializer)
183     }
184 }
185 
186 impl<'de> Deserialize<'de> for WebWindow {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,187     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
188     where
189         D: Deserializer<'de>,
190     {
191         Deserialize::deserialize(deserializer).map(|WebWindowObject { id }| WebWindow(id))
192     }
193 }
194 
195 #[cfg(test)]
196 mod tests {
197     use super::*;
198     use crate::test::{assert_ser, assert_ser_de};
199     use serde_json::{self, json};
200 
201     #[test]
test_json_date()202     fn test_json_date() {
203         assert_ser_de(&Date(1234), json!(1234));
204     }
205 
206     #[test]
test_json_date_invalid()207     fn test_json_date_invalid() {
208         assert!(serde_json::from_value::<Date>(json!("2018-01-01")).is_err());
209     }
210 
211     #[test]
test_json_frame_id_short()212     fn test_json_frame_id_short() {
213         assert_ser_de(&FrameId::Short(1234), json!(1234));
214     }
215 
216     #[test]
test_json_frame_id_webelement()217     fn test_json_frame_id_webelement() {
218         assert_ser(
219             &FrameId::Element(WebElement("elem".into())),
220             json!({ELEMENT_KEY: "elem"}),
221         );
222     }
223 
224     #[test]
test_json_frame_id_invalid()225     fn test_json_frame_id_invalid() {
226         assert!(serde_json::from_value::<FrameId>(json!(true)).is_err());
227     }
228 
229     #[test]
test_json_locator_strategy_css_selector()230     fn test_json_locator_strategy_css_selector() {
231         assert_ser_de(&LocatorStrategy::CSSSelector, json!("css selector"));
232     }
233 
234     #[test]
test_json_locator_strategy_link_text()235     fn test_json_locator_strategy_link_text() {
236         assert_ser_de(&LocatorStrategy::LinkText, json!("link text"));
237     }
238 
239     #[test]
test_json_locator_strategy_partial_link_text()240     fn test_json_locator_strategy_partial_link_text() {
241         assert_ser_de(
242             &LocatorStrategy::PartialLinkText,
243             json!("partial link text"),
244         );
245     }
246 
247     #[test]
test_json_locator_strategy_tag_name()248     fn test_json_locator_strategy_tag_name() {
249         assert_ser_de(&LocatorStrategy::TagName, json!("tag name"));
250     }
251 
252     #[test]
test_json_locator_strategy_xpath()253     fn test_json_locator_strategy_xpath() {
254         assert_ser_de(&LocatorStrategy::XPath, json!("xpath"));
255     }
256 
257     #[test]
test_json_locator_strategy_invalid()258     fn test_json_locator_strategy_invalid() {
259         assert!(serde_json::from_value::<LocatorStrategy>(json!("foo")).is_err());
260     }
261 
262     #[test]
test_json_shadowroot()263     fn test_json_shadowroot() {
264         assert_ser_de(&ShadowRoot("shadow".into()), json!({SHADOW_KEY: "shadow"}));
265     }
266 
267     #[test]
test_json_shadowroot_invalid()268     fn test_json_shadowroot_invalid() {
269         assert!(serde_json::from_value::<ShadowRoot>(json!({"invalid":"shadow"})).is_err());
270     }
271 
272     #[test]
test_json_webelement()273     fn test_json_webelement() {
274         assert_ser_de(&WebElement("elem".into()), json!({ELEMENT_KEY: "elem"}));
275     }
276 
277     #[test]
test_json_webelement_invalid()278     fn test_json_webelement_invalid() {
279         assert!(serde_json::from_value::<WebElement>(json!({"invalid": "elem"})).is_err());
280     }
281 
282     #[test]
test_json_webframe()283     fn test_json_webframe() {
284         assert_ser_de(&WebFrame("frame".into()), json!({FRAME_KEY: "frame"}));
285     }
286 
287     #[test]
test_json_webframe_invalid()288     fn test_json_webframe_invalid() {
289         assert!(serde_json::from_value::<WebFrame>(json!({"invalid": "frame"})).is_err());
290     }
291 
292     #[test]
test_json_webwindow()293     fn test_json_webwindow() {
294         assert_ser_de(&WebWindow("window".into()), json!({WINDOW_KEY: "window"}));
295     }
296 
297     #[test]
test_json_webwindow_invalid()298     fn test_json_webwindow_invalid() {
299         assert!(serde_json::from_value::<WebWindow>(json!({"invalid": "window"})).is_err());
300     }
301 }
302