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