--- a/Cargo.lock
+++ b/Cargo.lock
@@ -98,16 +98,24 @@ dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "base64"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1568,16 +1576,27 @@ name = "serde_derive_internals"
version = "0.19.0"
source = "git+https://github.com/gankro/serde?branch=deserialize_from_enums4#93e24f268ab99c0df10e2183587284e02ca30e9e"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
+name = "serde_json"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "servo_arc"
version = "0.1.1"
dependencies = [
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -2006,21 +2025,24 @@ dependencies = [
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "webdriver"
version = "0.35.0"
dependencies = [
+ "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)",
+ "serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "webrender"
version = "0.57.0"
@@ -2189,16 +2211,17 @@ dependencies = [
[metadata]
"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29069a9b483f7780aebb55dafb360c6225eefdc1f98c8d336a65148fd10c37b1"
"checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2"
"checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21"
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
+"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
"checksum bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3fb369af639822830328794eba2501b3479652fcd021b2aeb1ed4984202afd"
"checksum bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)" = "603ed8d8392ace9581e834e26bd09799bf1e989a79bd1aedbb893e72962bdc6e"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707"
"checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75"
@@ -2334,16 +2357,17 @@ dependencies = [
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918"
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)" = "<none>"
"checksum serde_derive_internals 0.19.0 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)" = "<none>"
+"checksum serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57781ed845b8e742fc2bf306aba8e3b408fe8c366b900e3769fbc39f49eb8b39"
"checksum simd 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd0805c7363ab51a829a1511ad24b6ed0349feaa756c4bc2f977f9f496e6673"
"checksum siphasher 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ffc669b726f2bc9a3bcff66e5e23b56ba6bf70e22a34c3d7b6d0b3450b65b84"
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "79b776f00dfe01df905fa3b2eaa1659522e99e3fc4a7b1334171622205c4bdcf"
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
--- a/testing/webdriver/Cargo.toml
+++ b/testing/webdriver/Cargo.toml
@@ -5,16 +5,19 @@ authors = ["Mozilla"]
description = "Library implementing the wire protocol for the W3C WebDriver specification."
keywords = ["webdriver", "browser", "automation", "protocol", "w3c"]
documentation = "https://docs.rs/webdriver"
repository = "https://hg.mozilla.org/mozilla-central/file/tip/testing/webdriver"
readme = "README.md"
license = "MPL-2.0"
[dependencies]
+base64 = "0.5"
cookie = { version = "0.10", default-features = false }
hyper = "0.10"
log = "0.4"
regex = "0.2"
-rustc-serialize = "0.3"
+serde = "1.0"
+serde_json = "1.0"
+serde_derive = "1.0"
time = "0.1"
unicode-segmentation = "1.1.0"
url = "1"
--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,660 +1,445 @@
-use command::Parameters;
-use common::{Nullable, WebElement};
-use error::{WebDriverResult, WebDriverError, ErrorStatus};
-use rustc_serialize::json::{ToJson, Json};
-use unicode_segmentation::UnicodeSegmentation;
-use std::collections::BTreeMap;
+use common::WebElement;
+use serde::{Deserialize, Deserializer};
+use serde_json::{Value, Map};
use std::default::Default;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize)]
pub struct ActionSequence {
- pub id: Nullable<String>,
+ pub id: Option<String>,
pub actions: ActionsType
}
-impl Parameters for ActionSequence {
- fn from_json(body: &Json) -> WebDriverResult<ActionSequence> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Actions chain was not an object");
-
- let type_name = try_opt!(try_opt!(data.get("type"),
- ErrorStatus::InvalidArgument,
- "Missing type parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter ;type' was not a string");
-
- let id = match data.get("id") {
- Some(x) => Some(try_opt!(x.as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'id' was not a string").to_owned()),
- None => None
- };
-
-
- // Note that unlike the spec we get the pointer parameters in ActionsType::from_json
+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>,
+ },
+ }
- let actions = match type_name {
- "none" | "key" | "pointer" => try!(ActionsType::from_json(&body)),
- _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Invalid action type"))
- };
-
- Ok(ActionSequence {
- id: id.into(),
- actions: actions
- })
- }
-}
-
-impl ToJson for ActionSequence {
- fn to_json(&self) -> Json {
- let mut data: BTreeMap<String, Json> = BTreeMap::new();
- data.insert("id".into(), self.id.to_json());
- let (action_type, actions) = match self.actions {
- ActionsType::Null(ref actions) => {
- ("none",
- actions.iter().map(|x| x.to_json()).collect::<Vec<Json>>())
- }
- ActionsType::Key(ref actions) => {
- ("key",
- actions.iter().map(|x| x.to_json()).collect::<Vec<Json>>())
- }
- ActionsType::Pointer(ref parameters, ref actions) => {
- data.insert("parameters".into(), parameters.to_json());
- ("pointer",
- actions.iter().map(|x| x.to_json()).collect::<Vec<Json>>())
+ match Helper::deserialize(deserializer)? {
+ Helper::Null { id, actions } => {
+ Ok(ActionSequence {
+ id: id,
+ actions: ActionsType::Null{actions},
+ })
}
- };
- data.insert("type".into(), action_type.to_json());
- data.insert("actions".into(), actions.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
-pub enum ActionsType {
- Null(Vec<NullActionItem>),
- Key(Vec<KeyActionItem>),
- Pointer(PointerActionParameters, Vec<PointerActionItem>)
-}
-
-impl Parameters for ActionsType {
- fn from_json(body: &Json) -> WebDriverResult<ActionsType> {
- // These unwraps are OK as long as this is only called from ActionSequence::from_json
- let data = body.as_object().expect("Body should be a JSON Object");
- let actions_type = body.find("type").and_then(|x| x.as_string()).expect("Type should be a string");
- let actions_chain = try_opt!(try_opt!(data.get("actions"),
- ErrorStatus::InvalidArgument,
- "Missing actions parameter").as_array(),
- ErrorStatus::InvalidArgument,
- "Parameter 'actions' was not an array");
- match actions_type {
- "none" => {
- let mut actions = Vec::with_capacity(actions_chain.len());
- for action_body in actions_chain.iter() {
- actions.push(try!(NullActionItem::from_json(action_body)));
- };
- Ok(ActionsType::Null(actions))
- },
- "key" => {
- let mut actions = Vec::with_capacity(actions_chain.len());
- for action_body in actions_chain.iter() {
- actions.push(try!(KeyActionItem::from_json(action_body)));
- };
- Ok(ActionsType::Key(actions))
- },
- "pointer" => {
- let mut actions = Vec::with_capacity(actions_chain.len());
- let parameters = match data.get("parameters") {
- Some(x) => try!(PointerActionParameters::from_json(x)),
- None => Default::default()
- };
-
- for action_body in actions_chain.iter() {
- actions.push(try!(PointerActionItem::from_json(action_body)));
- }
- Ok(ActionsType::Pointer(parameters, actions))
+ Helper::Key { id, actions } => {
+ Ok(ActionSequence {
+ id: id,
+ actions: ActionsType::Key{actions},
+ })
}
- _ => panic!("Got unexpected action type after checking type")
+ Helper::Pointer { id, parameters, actions } => {
+ Ok(ActionSequence {
+ id: id,
+ actions: ActionsType::Pointer{parameters, actions},
+ })
+ }
}
}
}
-#[derive(Debug, PartialEq)]
+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>>())
+ }
+ ActionsType::Key {ref actions} => {
+ ("key",
+ actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
+ }
+ ActionsType::Pointer {ref parameters, ref actions} => {
+ data.insert("parameters".into(), parameters.into());
+ ("pointer",
+ actions.iter().map(|x| x.into()).collect::<Vec<Value>>())
+ }
+ };
+ data.insert("type".into(), action_type.into());
+ data.insert("actions".into(), actions.into());
+ Value::Object(data)
+ }
+}
+
+#[derive(Debug, PartialEq, Serialize)]
+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")]
pub enum PointerType {
Mouse,
Pen,
Touch,
}
-impl Parameters for PointerType {
- fn from_json(body: &Json) -> WebDriverResult<PointerType> {
- match body.as_string() {
- Some("mouse") => Ok(PointerType::Mouse),
- Some("pen") => Ok(PointerType::Pen),
- Some("touch") => Ok(PointerType::Touch),
- Some(_) => Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Unsupported pointer type"
- )),
- None => Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Pointer type was not a string"
- ))
+impl<'a> From<&'a PointerType> for Value {
+ fn from(params: &'a PointerType) -> Value {
+ match *params {
+ PointerType::Mouse => "mouse".into(),
+ PointerType::Pen => "pen".into(),
+ PointerType::Touch => "touch".into(),
}
}
}
-impl ToJson for PointerType {
- fn to_json(&self) -> Json {
- match *self {
- PointerType::Mouse => "mouse".to_json(),
- PointerType::Pen => "pen".to_json(),
- PointerType::Touch => "touch".to_json(),
- }.to_json()
- }
-}
-
impl Default for PointerType {
fn default() -> PointerType {
PointerType::Mouse
}
}
-#[derive(Debug, Default, PartialEq)]
+#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PointerActionParameters {
+ #[serde(rename="pointerType")]
pub pointer_type: PointerType
}
-impl Parameters for PointerActionParameters {
- fn from_json(body: &Json) -> WebDriverResult<PointerActionParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Parameter 'parameters' was not an object");
- let pointer_type = match data.get("pointerType") {
- Some(x) => try!(PointerType::from_json(x)),
- None => PointerType::default()
- };
- Ok(PointerActionParameters {
- pointer_type: pointer_type
- })
+impl<'a> From<&'a PointerActionParameters> for Value {
+ fn from(params: &'a PointerActionParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("pointerType".to_owned(),
+ (¶ms.pointer_type).into());
+ Value::Object(data)
}
}
-impl ToJson for PointerActionParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("pointerType".to_owned(),
- self.pointer_type.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
pub enum NullActionItem {
General(GeneralAction)
}
-impl Parameters for NullActionItem {
- fn from_json(body: &Json) -> WebDriverResult<NullActionItem> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Actions chain was not an object");
- let type_name = try_opt!(
- try_opt!(data.get("type"),
- ErrorStatus::InvalidArgument,
- "Missing 'type' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'type' was not a string");
- match type_name {
- "pause" => Ok(NullActionItem::General(
- try!(GeneralAction::from_json(body)))),
- _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Invalid type attribute"))
+impl<'a> From<&'a NullActionItem> for Value {
+ fn from(params: &'a NullActionItem) -> Value {
+ match *params {
+ NullActionItem::General(ref x) => x.into(),
}
}
}
-impl ToJson for NullActionItem {
- fn to_json(&self) -> Json {
- match self {
- &NullActionItem::General(ref x) => x.to_json(),
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
pub enum KeyActionItem {
General(GeneralAction),
Key(KeyAction)
}
-impl Parameters for KeyActionItem {
- fn from_json(body: &Json) -> WebDriverResult<KeyActionItem> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Key action item was not an object");
- let type_name = try_opt!(
- try_opt!(data.get("type"),
- ErrorStatus::InvalidArgument,
- "Missing 'type' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'type' was not a string");
- match type_name {
- "pause" => Ok(KeyActionItem::General(
- try!(GeneralAction::from_json(body)))),
- _ => Ok(KeyActionItem::Key(
- try!(KeyAction::from_json(body))))
+impl<'a> From<&'a KeyActionItem> for Value {
+ fn from(params: &'a KeyActionItem) -> Value {
+ match *params {
+ KeyActionItem::General(ref x) => x.into(),
+ KeyActionItem::Key(ref x) => x.into()
}
}
}
-impl ToJson for KeyActionItem {
- fn to_json(&self) -> Json {
- match *self {
- KeyActionItem::General(ref x) => x.to_json(),
- KeyActionItem::Key(ref x) => x.to_json()
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
pub enum PointerActionItem {
General(GeneralAction),
Pointer(PointerAction)
}
-impl Parameters for PointerActionItem {
- fn from_json(body: &Json) -> WebDriverResult<PointerActionItem> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Pointer action item was not an object");
- let type_name = try_opt!(
- try_opt!(data.get("type"),
- ErrorStatus::InvalidArgument,
- "Missing 'type' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'type' was not a string");
-
- match type_name {
- "pause" => Ok(PointerActionItem::General(try!(GeneralAction::from_json(body)))),
- _ => Ok(PointerActionItem::Pointer(try!(PointerAction::from_json(body))))
+impl<'a> From<&'a PointerActionItem> for Value {
+ fn from(params: &'a PointerActionItem) -> Value {
+ match *params {
+ PointerActionItem::General(ref x) => x.into(),
+ PointerActionItem::Pointer(ref x) => x.into()
}
}
}
-impl ToJson for PointerActionItem {
- fn to_json(&self) -> Json {
- match self {
- &PointerActionItem::General(ref x) => x.to_json(),
- &PointerActionItem::Pointer(ref x) => x.to_json()
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
pub enum GeneralAction {
Pause(PauseAction)
}
-impl Parameters for GeneralAction {
- fn from_json(body: &Json) -> WebDriverResult<GeneralAction> {
- match body.find("type").and_then(|x| x.as_string()) {
- Some("pause") => Ok(GeneralAction::Pause(try!(PauseAction::from_json(body)))),
- _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Invalid or missing type attribute"))
+impl<'a> From<&'a GeneralAction> for Value {
+ fn from(params: &'a GeneralAction) -> Value {
+ match *params {
+ GeneralAction::Pause(ref x) => x.into()
}
}
}
-impl ToJson for GeneralAction {
- fn to_json(&self) -> Json {
- match self {
- &GeneralAction::Pause(ref x) => x.to_json()
- }
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct PauseAction {
pub duration: u64
}
-impl Parameters for PauseAction {
- fn from_json(body: &Json) -> WebDriverResult<PauseAction> {
- let default = Json::U64(0);
- Ok(PauseAction {
- duration: try_opt!(body.find("duration").unwrap_or(&default).as_u64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'duration' was not a positive integer")
- })
- }
-}
-
-impl ToJson for PauseAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
+impl<'a> From<&'a PauseAction> for Value {
+ fn from(params: &'a PauseAction) -> Value {
+ let mut data = Map::new();
data.insert("type".to_owned(),
- "pause".to_json());
+ "pause".into());
data.insert("duration".to_owned(),
- self.duration.to_json());
- Json::Object(data)
+ params.duration.into());
+ Value::Object(data)
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
pub enum KeyAction {
+ #[serde(rename="keyUp")]
Up(KeyUpAction),
+ #[serde(rename="keyDown")]
Down(KeyDownAction)
}
-impl Parameters for KeyAction {
- fn from_json(body: &Json) -> WebDriverResult<KeyAction> {
- match body.find("type").and_then(|x| x.as_string()) {
- Some("keyDown") => Ok(KeyAction::Down(try!(KeyDownAction::from_json(body)))),
- Some("keyUp") => Ok(KeyAction::Up(try!(KeyUpAction::from_json(body)))),
- Some(_) | None => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Invalid type attribute value for key action"))
- }
- }
-}
-
-impl ToJson for KeyAction {
- fn to_json(&self) -> Json {
- match self {
- &KeyAction::Down(ref x) => x.to_json(),
- &KeyAction::Up(ref x) => x.to_json(),
+impl<'a> From<&'a KeyAction> for Value {
+ fn from(params: &'a KeyAction) -> Value {
+ match *params {
+ KeyAction::Down(ref x) => x.into(),
+ KeyAction::Up(ref x) => x.into(),
}
}
}
-fn validate_key_value(value_str: &str) -> WebDriverResult<String> {
- let mut graphemes = value_str.graphemes(true);
- let value = if let Some(g) = graphemes.next() {
- g
- } else {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Parameter 'value' was an empty string"))
- };
- if graphemes.next().is_some() {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Parameter 'value' contained multiple graphemes"))
- };
- Ok(value.to_string())
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct KeyUpAction {
pub value: String
}
-impl Parameters for KeyUpAction {
- fn from_json(body: &Json) -> WebDriverResult<KeyUpAction> {
- let value_str = try_opt!(
- try_opt!(body.find("value"),
- ErrorStatus::InvalidArgument,
- "Missing value parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'value' was not a string");
-
- let value = try!(validate_key_value(value_str));
- Ok(KeyUpAction {
- value: value
- })
+impl<'a> From<&'a KeyUpAction> for Value {
+ fn from(params: &'a KeyUpAction) -> Value {
+ let mut data = Map::new();
+ data.insert("type".to_owned(),
+ "keyUp".into());
+ data.insert("value".to_string(),
+ params.value.to_string().into());
+ Value::Object(data)
}
}
-impl ToJson for KeyUpAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("type".to_owned(),
- "keyUp".to_json());
- data.insert("value".to_string(),
- self.value.to_string().to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct KeyDownAction {
pub value: String
}
-impl Parameters for KeyDownAction {
- fn from_json(body: &Json) -> WebDriverResult<KeyDownAction> {
- let value_str = try_opt!(
- try_opt!(body.find("value"),
- ErrorStatus::InvalidArgument,
- "Missing value parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Parameter 'value' was not a string");
- let value = try!(validate_key_value(value_str));
- Ok(KeyDownAction {
- value: value
- })
+impl<'a> From<&'a KeyDownAction> for Value {
+ fn from(params: &'a KeyDownAction) -> Value {
+ let mut data = Map::new();
+ data.insert("type".to_owned(),
+ "keyDown".into());
+ data.insert("value".to_owned(),
+ params.value.to_string().into());
+ Value::Object(data)
}
}
-impl ToJson for KeyDownAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("type".to_owned(),
- "keyDown".to_json());
- data.insert("value".to_owned(),
- self.value.to_string().to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged, rename_all="lowercase")]
pub enum PointerOrigin {
Viewport,
Pointer,
Element(WebElement),
}
-impl Parameters for PointerOrigin {
- fn from_json(body: &Json) -> WebDriverResult<PointerOrigin> {
- match *body {
- Json::String(ref x) => {
- match &**x {
- "viewport" => Ok(PointerOrigin::Viewport),
- "pointer" => Ok(PointerOrigin::Pointer),
- _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Unknown pointer origin"))
- }
- },
- Json::Object(_) => Ok(PointerOrigin::Element(try!(WebElement::from_json(body)))),
- _ => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Pointer origin was not a string or an object"))
- }
- }
-}
-
-impl ToJson for PointerOrigin {
- fn to_json(&self) -> Json {
- match *self {
- PointerOrigin::Viewport => "viewport".to_json(),
- PointerOrigin::Pointer => "pointer".to_json(),
- PointerOrigin::Element(ref x) => x.to_json(),
+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(),
}
}
}
impl Default for PointerOrigin {
fn default() -> PointerOrigin {
PointerOrigin::Viewport
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+#[serde(tag = "type")]
pub enum PointerAction {
+ #[serde(rename="pointerUp")]
Up(PointerUpAction),
+ #[serde(rename="pointerDown")]
Down(PointerDownAction),
+ #[serde(rename="pointerMove")]
Move(PointerMoveAction),
+ #[serde(rename="pointerCancel")]
Cancel
}
-impl Parameters for PointerAction {
- fn from_json(body: &Json) -> WebDriverResult<PointerAction> {
- match body.find("type").and_then(|x| x.as_string()) {
- Some("pointerUp") => Ok(PointerAction::Up(try!(PointerUpAction::from_json(body)))),
- Some("pointerDown") => Ok(PointerAction::Down(try!(PointerDownAction::from_json(body)))),
- Some("pointerMove") => Ok(PointerAction::Move(try!(PointerMoveAction::from_json(body)))),
- Some("pointerCancel") => Ok(PointerAction::Cancel),
- Some(_) | None => Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Missing or invalid type argument for pointer action"))
- }
- }
-}
-
-impl ToJson for PointerAction {
- fn to_json(&self) -> Json {
- match self {
- &PointerAction::Down(ref x) => x.to_json(),
- &PointerAction::Up(ref x) => x.to_json(),
- &PointerAction::Move(ref x) => x.to_json(),
- &PointerAction::Cancel => {
- let mut data = BTreeMap::new();
+impl<'a> From<&'a PointerAction> for Value {
+ fn from(params: &'a PointerAction) -> Value {
+ match *params {
+ PointerAction::Down(ref x) => x.into(),
+ PointerAction::Up(ref x) => x.into(),
+ PointerAction::Move(ref x) => x.into(),
+ PointerAction::Cancel => {
+ let mut data = Map::new();
data.insert("type".to_owned(),
- "pointerCancel".to_json());
- Json::Object(data)
+ "pointerCancel".into());
+ Value::Object(data)
}
}
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct PointerUpAction {
pub button: u64,
}
-impl Parameters for PointerUpAction {
- fn from_json(body: &Json) -> WebDriverResult<PointerUpAction> {
- let button = try_opt!(
- try_opt!(body.find("button"),
- ErrorStatus::InvalidArgument,
- "Missing button parameter").as_u64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'button' was not a positive integer");
-
- Ok(PointerUpAction {
- button: button
- })
+impl<'a> From<&'a PointerUpAction> for Value {
+ fn from(params: &'a PointerUpAction) -> Value {
+ let mut data = Map::new();
+ data.insert("type".to_owned(),
+ "pointerUp".into());
+ data.insert("button".to_owned(), params.button.into());
+ Value::Object(data)
}
}
-impl ToJson for PointerUpAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("type".to_owned(),
- "pointerUp".to_json());
- data.insert("button".to_owned(), self.button.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct PointerDownAction {
pub button: u64,
}
-impl Parameters for PointerDownAction {
- fn from_json(body: &Json) -> WebDriverResult<PointerDownAction> {
- let button = try_opt!(
- try_opt!(body.find("button"),
- ErrorStatus::InvalidArgument,
- "Missing button parameter").as_u64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'button' was not a positive integer");
-
- Ok(PointerDownAction {
- button: button
- })
+impl<'a> From<&'a PointerDownAction> for Value {
+ fn from(params: &'a PointerDownAction) -> Value {
+ let mut data = Map::new();
+ data.insert("type".to_owned(),
+ "pointerDown".into());
+ data.insert("button".to_owned(), params.button.into());
+ Value::Object(data)
}
}
-impl ToJson for PointerDownAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("type".to_owned(),
- "pointerDown".to_json());
- data.insert("button".to_owned(), self.button.to_json());
- Json::Object(data)
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct PointerMoveAction {
+ pub duration: Option<u64>,
+ pub origin: PointerOrigin,
+ 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());
+ if let Some(duration) = params.duration {
+ data.insert("duration".to_owned(),
+ duration.into());
+ }
+
+ data.insert("origin".to_owned(), (¶ms.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)
}
}
-#[derive(Debug, PartialEq)]
-pub struct PointerMoveAction {
- pub duration: Nullable<u64>,
- pub origin: PointerOrigin,
- pub x: Nullable<i64>,
- pub y: Nullable<i64>
-}
+#[cfg(test)]
+mod test {
+ use serde_json;
+ use command::ActionsParameters;
+ use common::WebElement;
+ use super::*;
-impl Parameters for PointerMoveAction {
- fn from_json(body: &Json) -> WebDriverResult<PointerMoveAction> {
- let duration = match body.find("duration") {
- Some(duration) => Some(try_opt!(duration.as_u64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'duration' was not a positive integer")),
- None => None
-
- };
-
- let origin = match body.find("origin") {
- Some(o) => try!(PointerOrigin::from_json(o)),
- None => PointerOrigin::default()
- };
-
- let x = match body.find("x") {
- Some(x) => {
- Some(try_opt!(x.as_i64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'x' was not an integer"))
- },
- None => None
+ #[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
+ ),
+ }
+ }
+ }
+ ]
};
- let y = match body.find("y") {
- Some(y) => {
- Some(try_opt!(y.as_i64(),
- ErrorStatus::InvalidArgument,
- "Parameter 'y' was not an integer"))
- },
- None => None
- };
-
- Ok(PointerMoveAction {
- duration: duration.into(),
- origin: origin.into(),
- x: x.into(),
- y: y.into(),
- })
+ 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();
+ assert_eq!(expected, actual);
}
}
-
-impl ToJson for PointerMoveAction {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("type".to_owned(), "pointerMove".to_json());
- if self.duration.is_value() {
- data.insert("duration".to_owned(),
- self.duration.to_json());
- }
-
- data.insert("origin".to_owned(), self.origin.to_json());
-
- if self.x.is_value() {
- data.insert("x".to_owned(), self.x.to_json());
- }
- if self.y.is_value() {
- data.insert("y".to_owned(), self.y.to_json());
- }
- Json::Object(data)
- }
-}
--- a/testing/webdriver/src/capabilities.rs
+++ b/testing/webdriver/src/capabilities.rs
@@ -1,15 +1,14 @@
-use command::Parameters;
-use error::{ErrorStatus, WebDriverError, WebDriverResult};
-use rustc_serialize::json::{Json, ToJson};
-use std::collections::BTreeMap;
+use error::{WebDriverResult, WebDriverError, ErrorStatus};
+use std::convert::From;
+use serde_json::{Value, Map};
use url::Url;
-pub type Capabilities = BTreeMap<String, Json>;
+pub type Capabilities = Map<String, Value>;
/// Trait for objects that can be used to inspect browser capabilities
///
/// The main methods in this trait are called with a Capabilites object
/// resulting from a full set of potential capabilites for the session.
/// Given those Capabilities they return a property of the browser instance
/// that would be initiated. In many cases this will be independent of the
/// input, but in the case of e.g. browser version, it might depend on a
@@ -29,59 +28,71 @@ pub trait BrowserCapabilities {
/// Parameters are the actual browser version and the comparison string,
/// respectively. The format of the comparison string is implementation-defined.
fn compare_browser_version(&mut self, version: &str, comparison: &str) -> WebDriverResult<bool>;
/// Name of the platform/OS
fn platform_name(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
/// Whether insecure certificates are supported
fn accept_insecure_certs(&mut self, &Capabilities) -> WebDriverResult<bool>;
- fn accept_proxy(&mut self, proxy_settings: &BTreeMap<String, Json>, &Capabilities) -> WebDriverResult<bool>;
+ fn accept_proxy(&mut self, proxy_settings: &Map<String, Value>, &Capabilities) -> WebDriverResult<bool>;
/// Type check custom properties
///
/// Check that custom properties containing ":" have the correct data types.
/// Properties that are unrecognised must be ignored i.e. return without
/// error.
- fn validate_custom(&self, name: &str, value: &Json) -> WebDriverResult<()>;
+ fn validate_custom(&self, name: &str, value: &Value) -> WebDriverResult<()>;
/// Check if custom properties are accepted capabilites
///
/// Check that custom properties containing ":" are compatible with
/// the implementation.
- fn accept_custom(&mut self, name: &str, value: &Json, merged: &Capabilities) -> WebDriverResult<bool>;
+ fn accept_custom(&mut self, name: &str, value: &Value, merged: &Capabilities) -> WebDriverResult<bool>;
}
/// Trait to abstract over various version of the new session parameters
///
/// This trait is expected to be implemented on objects holding the capabilities
/// from a new session command.
pub trait CapabilitiesMatching {
/// Match the BrowserCapabilities against some candidate capabilites
///
/// Takes a BrowserCapabilites object and returns a set of capabilites that
/// are valid for that browser, if any, or None if there are no matching
/// capabilities.
fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
-> WebDriverResult<Option<Capabilities>>;
}
-#[derive(Debug, PartialEq)]
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
+pub struct SpecNewSessionParametersWrapper {
+ capabilities: SpecNewSessionParameters
+}
+
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct SpecNewSessionParameters {
pub alwaysMatch: Capabilities,
pub firstMatch: Vec<Capabilities>,
}
+impl From<SpecNewSessionParametersWrapper> for SpecNewSessionParameters {
+ fn from(wrapper: SpecNewSessionParametersWrapper) -> SpecNewSessionParameters {
+ wrapper.capabilities
+ }
+}
+
+
impl SpecNewSessionParameters {
fn validate<T: BrowserCapabilities>(&self,
mut capabilities: Capabilities,
browser_capabilities: &T) -> WebDriverResult<Capabilities> {
// Filter out entries with the value `null`
let null_entries = capabilities
.iter()
- .filter(|&(_, ref value)| **value == Json::Null)
+ .filter(|&(_, ref value)| **value == Value::Null)
.map(|(k, _)| k.clone())
.collect::<Vec<String>>();
for key in null_entries {
capabilities.remove(&key);
}
for (key, value) in capabilities.iter() {
match &**key {
@@ -115,19 +126,19 @@ impl SpecNewSessionParameters {
try!(browser_capabilities.validate_custom(x, value));
}
}
}
}
Ok(capabilities)
}
- fn validate_page_load_strategy(value: &Json) -> WebDriverResult<()> {
+ fn validate_page_load_strategy(value: &Value) -> WebDriverResult<()> {
match value {
- &Json::String(ref x) => {
+ &Value::String(ref x) => {
match &**x {
"normal" |
"eager" |
"none" => {},
x => {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("Invalid page load strategy: {}", x)))
@@ -135,38 +146,38 @@ impl SpecNewSessionParameters {
}
}
_ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
"pageLoadStrategy is not a string"))
}
Ok(())
}
- fn validate_proxy(proxy_value: &Json) -> WebDriverResult<()> {
+ fn validate_proxy(proxy_value: &Value) -> WebDriverResult<()> {
let obj = try_opt!(proxy_value.as_object(),
ErrorStatus::InvalidArgument,
"proxy is not an object");
for (key, value) in obj.iter() {
match &**key {
- "proxyType" => match value.as_string() {
+ "proxyType" => match value.as_str() {
Some("pac") |
Some("direct") |
Some("autodetect") |
Some("system") |
Some("manual") => {},
Some(x) => return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("Invalid proxyType value: {}", x))),
None => return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("proxyType is not a string: {}", value))),
},
- "proxyAutoconfigUrl" => match value.as_string() {
+ "proxyAutoconfigUrl" => match value.as_str() {
Some(x) => {
Url::parse(x).or(Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("proxyAutoconfigUrl is not a valid URL: {}", x))))?;
},
None => return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
"proxyAutoconfigUrl is not a string"
@@ -189,21 +200,21 @@ impl SpecNewSessionParameters {
ErrorStatus::InvalidArgument,
format!("Invalid proxy configuration entry: {}", x)))
}
}
Ok(())
}
- fn validate_no_proxy(value: &Json) -> WebDriverResult<()> {
+ fn validate_no_proxy(value: &Value) -> WebDriverResult<()> {
match value.as_array() {
Some(hosts) => {
for host in hosts {
- match host.as_string() {
+ match host.as_str() {
Some(_) => {},
None => return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("noProxy item is not a string: {}", host)
))
}
}
},
@@ -213,18 +224,18 @@ impl SpecNewSessionParameters {
))
}
Ok(())
}
/// Validate whether a named capability is JSON value is a string containing a host
/// and possible port
- fn validate_host(value: &Json, entry: &str) -> WebDriverResult<()> {
- match value.as_string() {
+ fn validate_host(value: &Value, entry: &str) -> WebDriverResult<()> {
+ match value.as_str() {
Some(host) => {
if host.contains("://") {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
format!("{} must not contain a scheme: {}", entry, host)));
}
// Temporarily add a scheme so the host can be parsed as URL
@@ -248,17 +259,17 @@ impl SpecNewSessionParameters {
ErrorStatus::InvalidArgument,
format!("{} is not a string: {}", entry, value)
))
}
Ok(())
}
- fn validate_timeouts(value: &Json) -> WebDriverResult<()> {
+ fn validate_timeouts(value: &Value) -> WebDriverResult<()> {
let obj = try_opt!(
value.as_object(),
ErrorStatus::InvalidArgument,
"timeouts capability is not an object"
);
for (key, value) in obj.iter() {
match &**key {
@@ -283,19 +294,19 @@ impl SpecNewSessionParameters {
))
}
}
}
Ok(())
}
- fn validate_unhandled_prompt_behaviour(value: &Json) -> WebDriverResult<()> {
+ fn validate_unhandled_prompt_behaviour(value: &Value) -> WebDriverResult<()> {
let behaviour = try_opt!(
- value.as_string(),
+ value.as_str(),
ErrorStatus::InvalidArgument,
format!("unhandledPromptBehavior is not a string: {}", value)
);
match behaviour {
"dismiss" | "accept" => {}
x => {
return Err(WebDriverError::new(
@@ -304,101 +315,55 @@ impl SpecNewSessionParameters {
))
}
}
Ok(())
}
}
-impl Parameters for SpecNewSessionParameters {
- fn from_json(body: &Json) -> WebDriverResult<SpecNewSessionParameters> {
- let data = try_opt!(
- body.as_object(),
- ErrorStatus::UnknownError,
- format!("Malformed capabilities, message body is not an object: {}", body)
- );
-
- let capabilities = try_opt!(
- try_opt!(
- data.get("capabilities"),
- ErrorStatus::InvalidArgument,
- "Malformed capabilities, missing \"capabilities\" field"
- ).as_object(),
- ErrorStatus::InvalidArgument,
- "Malformed capabilities, \"capabilities\" field is not an object}"
- );
-
- let default_always_match = Json::Object(Capabilities::new());
- let always_match = try_opt!(
- capabilities
- .get("alwaysMatch")
- .unwrap_or(&default_always_match)
- .as_object(),
- ErrorStatus::InvalidArgument,
- "Malformed capabilities, alwaysMatch field is not an object"
- );
- let default_first_matches = Json::Array(vec![]);
- let first_matches = try_opt!(
- capabilities
- .get("firstMatch")
- .unwrap_or(&default_first_matches)
- .as_array(),
- ErrorStatus::InvalidArgument,
- "Malformed capabilities, firstMatch field is not an array"
- ).iter()
- .map(|x| {
- x.as_object().map(|x| x.clone()).ok_or(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "Malformed capabilities, firstMatch entry is not an object",
- ))
- })
- .collect::<WebDriverResult<Vec<Capabilities>>>()?;
-
- return Ok(SpecNewSessionParameters {
- alwaysMatch: always_match.clone(),
- firstMatch: first_matches,
- });
- }
-}
-
-impl ToJson for SpecNewSessionParameters {
- fn to_json(&self) -> Json {
- let mut body = BTreeMap::new();
- let mut capabilities = BTreeMap::new();
- capabilities.insert("alwaysMatch".into(), self.alwaysMatch.to_json());
- capabilities.insert("firstMatch".into(), self.firstMatch.to_json());
- body.insert("capabilities".into(), capabilities.to_json());
- Json::Object(body)
+impl<'a> From<&'a SpecNewSessionParameters> for Value {
+ fn from(params: &'a SpecNewSessionParameters) -> Value {
+ let mut body = Map::new();
+ let mut capabilities = Map::new();
+ capabilities.insert("alwaysMatch".into(), Value::Object(params.alwaysMatch.clone()));
+ capabilities.insert("firstMatch".into(), Value::Array(params.firstMatch.clone()
+ .into_iter()
+ .map(|x| Value::Object(x))
+ .collect::<Vec<_>>()));
+ body.insert("capabilities".into(), Value::Object(capabilities));
+ Value::Object(body)
}
}
impl CapabilitiesMatching for SpecNewSessionParameters {
fn match_browser<T: BrowserCapabilities>(
&self,
browser_capabilities: &mut T,
) -> WebDriverResult<Option<Capabilities>> {
- let default = vec![BTreeMap::new()];
+ let default = vec![Map::new()];
let capabilities_list = if self.firstMatch.len() > 0 {
&self.firstMatch
} else {
&default
};
let merged_capabilities = capabilities_list
.iter()
.map(|first_match_entry| {
if first_match_entry.keys().any(|k| self.alwaysMatch.contains_key(k)) {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
"firstMatch key shadowed a value in alwaysMatch",
));
}
let mut merged = self.alwaysMatch.clone();
- merged.append(&mut first_match_entry.clone());
+ for (key, value) in first_match_entry.clone().into_iter() {
+ merged.insert(key, value);
+ }
Ok(merged)
})
.map(|merged| {
merged.and_then(|x| self.validate(x, browser_capabilities))
})
.collect::<WebDriverResult<Vec<Capabilities>>>()?;
let selected = merged_capabilities
@@ -409,58 +374,58 @@ impl CapabilitiesMatching for SpecNewSes
for (key, value) in merged.iter() {
match &**key {
"browserName" => {
let browserValue = browser_capabilities
.browser_name(merged)
.ok()
.and_then(|x| x);
- if value.as_string() != browserValue.as_ref().map(|x| &**x) {
+ if value.as_str() != browserValue.as_ref().map(|x| &**x) {
return None;
}
}
"browserVersion" => {
let browserValue = browser_capabilities
.browser_version(merged)
.ok()
.and_then(|x| x);
// We already validated this was a string
- let version_cond = value.as_string().unwrap_or("");
+ let version_cond = value.as_str().unwrap_or("");
if let Some(version) = browserValue {
if !browser_capabilities
.compare_browser_version(&*version, version_cond)
.unwrap_or(false)
{
return None;
}
} else {
return None;
}
}
"platformName" => {
let browserValue = browser_capabilities
.platform_name(merged)
.ok()
.and_then(|x| x);
- if value.as_string() != browserValue.as_ref().map(|x| &**x) {
+ if value.as_str() != browserValue.as_ref().map(|x| &**x) {
return None;
}
}
"acceptInsecureCerts" => {
- if value.as_boolean().unwrap_or(false) &&
+ if value.as_bool().unwrap_or(false) &&
!browser_capabilities
.accept_insecure_certs(merged)
.unwrap_or(false)
{
return None;
}
}
"proxy" => {
- let default = BTreeMap::new();
+ let default = Map::new();
let proxy = value.as_object().unwrap_or(&default);
if !browser_capabilities
.accept_proxy(&proxy, merged)
.unwrap_or(false)
{
return None;
}
}
@@ -482,93 +447,61 @@ impl CapabilitiesMatching for SpecNewSes
return Some(merged);
})
.next()
.map(|x| x.clone());
Ok(selected)
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct LegacyNewSessionParameters {
pub desired: Capabilities,
pub required: Capabilities,
}
impl CapabilitiesMatching for LegacyNewSessionParameters {
fn match_browser<T: BrowserCapabilities>(
&self,
browser_capabilities: &mut T,
) -> WebDriverResult<Option<Capabilities>> {
// For now don't do anything much, just merge the
// desired and required and return the merged list.
- let mut capabilities: Capabilities = BTreeMap::new();
+ let mut capabilities: Capabilities = Map::new();
self.required.iter().chain(self.desired.iter()).fold(
&mut capabilities,
|caps, (key, value)| {
if !caps.contains_key(key) {
caps.insert(key.clone(), value.clone());
}
caps
},
);
browser_capabilities.init(&capabilities);
Ok(Some(capabilities))
}
}
-impl Parameters for LegacyNewSessionParameters {
- fn from_json(body: &Json) -> WebDriverResult<LegacyNewSessionParameters> {
- let data = try_opt!(
- body.as_object(),
- ErrorStatus::UnknownError,
- format!("Malformed legacy capabilities, message body is not an object: {}", body)
- );
-
- let desired = if let Some(capabilities) = data.get("desiredCapabilities") {
- try_opt!(
- capabilities.as_object(),
- ErrorStatus::InvalidArgument,
- "Malformed legacy capabilities, desiredCapabilities field is not an object"
- ).clone()
- } else {
- BTreeMap::new()
- };
-
- let required = if let Some(capabilities) = data.get("requiredCapabilities") {
- try_opt!(
- capabilities.as_object(),
- ErrorStatus::InvalidArgument,
- "Malformed legacy capabilities, requiredCapabilities field is not an object"
- ).clone()
- } else {
- BTreeMap::new()
- };
-
- Ok(LegacyNewSessionParameters { desired, required })
- }
-}
-
-impl ToJson for LegacyNewSessionParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("desiredCapabilities".to_owned(), self.desired.to_json());
- data.insert("requiredCapabilities".to_owned(), self.required.to_json());
- Json::Object(data)
+impl<'a> From<&'a LegacyNewSessionParameters> for Value {
+ fn from(params: &'a LegacyNewSessionParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("desiredCapabilities".to_owned(), Value::Object(params.desired.clone()));
+ data.insert("requiredCapabilities".to_owned(), Value::Object(params.required.clone()));
+ Value::Object(data)
}
}
#[cfg(test)]
mod tests {
- use rustc_serialize::json::Json;
+ use serde_json::{self, Value};
use super::{SpecNewSessionParameters, WebDriverResult};
fn validate_proxy(value: &str) -> WebDriverResult<()> {
- let data = Json::from_str(value).unwrap();
+ let data = serde_json::from_str::<Value>(value).unwrap();
SpecNewSessionParameters::validate_proxy(&data)
}
#[test]
fn test_validate_proxy() {
// proxy hosts
validate_proxy("{\"httpProxy\": \"127.0.0.1\"}").unwrap();
validate_proxy("{\"httpProxy\": \"127.0.0.1:\"}").unwrap();
--- a/testing/webdriver/src/command.rs
+++ b/testing/webdriver/src/command.rs
@@ -1,18 +1,17 @@
-use actions::{ActionSequence};
-use capabilities::{SpecNewSessionParameters, LegacyNewSessionParameters,
+use actions::ActionSequence;
+use capabilities::{SpecNewSessionParametersWrapper, SpecNewSessionParameters, LegacyNewSessionParameters,
CapabilitiesMatching, BrowserCapabilities, Capabilities};
-use common::{Date, Nullable, WebElement, FrameId, LocatorStrategy};
+use common::{Date, WebElement, FrameId, LocatorStrategy};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::{Route, WebDriverExtensionRoute, VoidWebDriverExtensionRoute};
use regex::Captures;
-use rustc_serialize::json;
-use rustc_serialize::json::{ToJson, Json};
-use std::collections::BTreeMap;
+use serde_json::{self, Value, Map};
+use std::convert::From;
#[derive(Debug, PartialEq)]
pub enum WebDriverCommand<T: WebDriverExtensionCommand> {
NewSession(NewSessionParameters),
DeleteSession,
Get(GetParameters),
GetCurrentUrl,
GoBack,
@@ -60,30 +59,30 @@ pub enum WebDriverCommand<T: WebDriverEx
ElementSendKeys(WebElement, SendKeysParameters),
PerformActions(ActionsParameters),
ReleaseActions,
DismissAlert,
AcceptAlert,
GetAlertText,
SendAlertText(SendKeysParameters),
TakeScreenshot,
- TakeElementScreenshot(WebElement),
+ TakeElementScreenshot(TakeScreenshotParameters),
Status,
Extension(T)
}
pub trait WebDriverExtensionCommand : Clone + Send + PartialEq {
- fn parameters_json(&self) -> Option<Json>;
+ fn parameters_json(&self) -> Option<Value>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct VoidWebDriverExtensionCommand;
impl WebDriverExtensionCommand for VoidWebDriverExtensionCommand {
- fn parameters_json(&self) -> Option<Json> {
+ fn parameters_json(&self) -> Option<Value> {
panic!("No extensions implemented");
}
}
#[derive(Debug, PartialEq)]
pub struct WebDriverMessage <U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> {
pub session_id: Option<String>,
pub command: WebDriverCommand<U::Command>,
@@ -101,80 +100,79 @@ impl<U: WebDriverExtensionRoute> WebDriv
pub fn from_http(match_type: Route<U>,
params: &Captures,
raw_body: &str,
requires_body: bool)
-> WebDriverResult<WebDriverMessage<U>> {
let session_id = WebDriverMessage::<U>::get_session_id(params);
let body_data = try!(WebDriverMessage::<U>::decode_body(raw_body, requires_body));
-
let command = match match_type {
Route::NewSession => {
- let parameters: NewSessionParameters = try!(Parameters::from_json(&body_data));
- WebDriverCommand::NewSession(parameters)
+ let parameters: NewSessionParametersWrapper = serde_json::from_str(raw_body)?;
+ WebDriverCommand::NewSession(parameters.into())
},
Route::DeleteSession => WebDriverCommand::DeleteSession,
Route::Get => {
- let parameters: GetParameters = try!(Parameters::from_json(&body_data));
+ let parameters: GetParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::Get(parameters)
},
Route::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
Route::GoBack => WebDriverCommand::GoBack,
Route::GoForward => WebDriverCommand::GoForward,
Route::Refresh => WebDriverCommand::Refresh,
Route::GetTitle => WebDriverCommand::GetTitle,
Route::GetPageSource => WebDriverCommand::GetPageSource,
Route::GetWindowHandle => WebDriverCommand::GetWindowHandle,
Route::GetWindowHandles => WebDriverCommand::GetWindowHandles,
Route::CloseWindow => WebDriverCommand::CloseWindow,
Route::GetTimeouts => WebDriverCommand::GetTimeouts,
Route::SetTimeouts => {
- let parameters: TimeoutsParameters = try!(Parameters::from_json(&body_data));
+ let parameters: TimeoutsParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::SetTimeouts(parameters)
},
Route::GetWindowRect | Route::GetWindowPosition | Route::GetWindowSize => WebDriverCommand::GetWindowRect,
Route::SetWindowRect | Route::SetWindowPosition | Route::SetWindowSize => {
- let parameters: WindowRectParameters = Parameters::from_json(&body_data)?;
+ let parameters: WindowRectParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::SetWindowRect(parameters)
},
Route::MinimizeWindow => WebDriverCommand::MinimizeWindow,
Route::MaximizeWindow => WebDriverCommand::MaximizeWindow,
Route::FullscreenWindow => WebDriverCommand::FullscreenWindow,
Route::SwitchToWindow => {
- let parameters: SwitchToWindowParameters = try!(Parameters::from_json(&body_data));
+ let parameters: SwitchToWindowParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::SwitchToWindow(parameters)
}
Route::SwitchToFrame => {
- let parameters: SwitchToFrameParameters = try!(Parameters::from_json(&body_data));
+ let parameters: SwitchToFrameParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::SwitchToFrame(parameters)
},
Route::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
Route::FindElement => {
- let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+ let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::FindElement(parameters)
},
Route::FindElements => {
- let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+ let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::FindElements(parameters)
},
Route::FindElementElement => {
let element_id = try_opt!(params.name("elementId"),
ErrorStatus::InvalidArgument,
"Missing elementId parameter");
let element = WebElement::new(element_id.as_str().into());
- let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+ let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::FindElementElement(element, parameters)
},
Route::FindElementElements => {
let element_id = try_opt!(params.name("elementId"),
ErrorStatus::InvalidArgument,
"Missing elementId parameter");
let element = WebElement::new(element_id.as_str().into());
- let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
+ let parameters: LocatorParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::FindElementElements(element, parameters)
},
Route::GetActiveElement => WebDriverCommand::GetActiveElement,
Route::IsDisplayed => {
let element_id = try_opt!(params.name("elementId"),
ErrorStatus::InvalidArgument,
"Missing elementId parameter");
let element = WebElement::new(element_id.as_str().into());
@@ -266,116 +264,115 @@ impl<U: WebDriverExtensionRoute> WebDriv
let element = WebElement::new(element_id.as_str().into());
WebDriverCommand::ElementClear(element)
},
Route::ElementSendKeys => {
let element_id = try_opt!(params.name("elementId"),
ErrorStatus::InvalidArgument,
"Missing elementId parameter");
let element = WebElement::new(element_id.as_str().into());
- let parameters: SendKeysParameters = try!(Parameters::from_json(&body_data));
+ let parameters: SendKeysParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::ElementSendKeys(element, parameters)
},
Route::ExecuteScript => {
- let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
+ let parameters: JavascriptCommandParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::ExecuteScript(parameters)
},
Route::ExecuteAsyncScript => {
- let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
+ let parameters: JavascriptCommandParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::ExecuteAsyncScript(parameters)
},
Route::GetCookies => {
WebDriverCommand::GetCookies
},
Route::GetNamedCookie => {
let name = try_opt!(params.name("name"),
ErrorStatus::InvalidArgument,
"Missing 'name' parameter").as_str().into();
WebDriverCommand::GetNamedCookie(name)
},
Route::AddCookie => {
- let parameters: AddCookieParameters = try!(Parameters::from_json(&body_data));
- WebDriverCommand::AddCookie(parameters)
+ let parameters: AddCookieParametersWrapper = serde_json::from_str(raw_body)?;
+ WebDriverCommand::AddCookie(parameters.cookie)
},
Route::DeleteCookies => {
WebDriverCommand::DeleteCookies
},
Route::DeleteCookie => {
let name = try_opt!(params.name("name"),
ErrorStatus::InvalidArgument,
"Missing name parameter").as_str().into();
WebDriverCommand::DeleteCookie(name)
},
Route::PerformActions => {
- let parameters: ActionsParameters = try!(Parameters::from_json(&body_data));
+ let parameters: ActionsParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::PerformActions(parameters)
},
Route::ReleaseActions => {
WebDriverCommand::ReleaseActions
},
Route::DismissAlert => {
WebDriverCommand::DismissAlert
},
Route::AcceptAlert => {
WebDriverCommand::AcceptAlert
},
Route::GetAlertText => {
WebDriverCommand::GetAlertText
},
Route::SendAlertText => {
- let parameters: SendKeysParameters = try!(Parameters::from_json(&body_data));
+ let parameters: SendKeysParameters = serde_json::from_str(raw_body)?;
WebDriverCommand::SendAlertText(parameters)
},
Route::TakeScreenshot => WebDriverCommand::TakeScreenshot,
Route::TakeElementScreenshot => {
- let element_id = try_opt!(params.name("elementId"),
- ErrorStatus::InvalidArgument,
- "Missing elementId parameter");
- let element = WebElement::new(element_id.as_str().into());
- WebDriverCommand::TakeElementScreenshot(element)
+ let parameters: TakeScreenshotParameters = serde_json::from_str(raw_body)?;
+ WebDriverCommand::TakeElementScreenshot(parameters)
},
Route::Status => WebDriverCommand::Status,
Route::Extension(ref extension) => {
try!(extension.command(params, &body_data))
}
};
Ok(WebDriverMessage::new(session_id, command))
}
fn get_session_id(params: &Captures) -> Option<String> {
params.name("sessionId").map(|x| x.as_str().into())
}
- fn decode_body(body: &str, requires_body: bool) -> WebDriverResult<Json> {
+ fn decode_body(body: &str, requires_body: bool) -> WebDriverResult<Value> {
if requires_body {
- match Json::from_str(body) {
- Ok(x @ Json::Object(_)) => Ok(x),
+ match serde_json::from_str(body) {
+ Ok(x @ Value::Object(_)) => Ok(x),
Ok(_) => {
Err(WebDriverError::new(ErrorStatus::InvalidArgument,
"Body was not a JSON Object"))
}
- Err(json::ParserError::SyntaxError(_, line, col)) => {
- let msg = format!("Failed to decode request as JSON: \"{}\"", body);
- let stack = format!("Syntax error at :{}:{}", line, col);
- Err(WebDriverError::new_with_stack(ErrorStatus::InvalidArgument, msg, stack))
- }
- Err(json::ParserError::IoError(e)) => {
- Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- format!("I/O error whilst decoding body: {}", e)))
+ Err(e) => {
+ if e.is_io() {
+ Err(WebDriverError::new(ErrorStatus::InvalidArgument,
+ format!("I/O error whilst decoding body: {}", e)))
+ } else {
+ let msg = format!("Failed to decode request as JSON: {}", body);
+ let stack = format!("Syntax error at :{}:{}", e.line(), e.column());
+ Err(WebDriverError::new_with_stack(ErrorStatus::InvalidArgument,
+ msg, stack))
+ }
}
}
} else {
- Ok(Json::Null)
+ Ok(Value::Null)
}
}
}
-impl <U:WebDriverExtensionRoute> ToJson for WebDriverMessage<U> {
- fn to_json(&self) -> Json {
- let parameters = match self.command {
+impl <U:WebDriverExtensionRoute> From<WebDriverMessage<U>> for Value {
+ fn from(msg: WebDriverMessage<U>) -> Value {
+ let parameters = match msg.command {
WebDriverCommand::AcceptAlert |
WebDriverCommand::CloseWindow |
WebDriverCommand::ReleaseActions |
WebDriverCommand::DeleteCookie(_) |
WebDriverCommand::DeleteCookies |
WebDriverCommand::DeleteSession |
WebDriverCommand::DismissAlert |
WebDriverCommand::ElementClear(_) |
@@ -410,728 +407,336 @@ impl <U:WebDriverExtensionRoute> ToJson
WebDriverCommand::Refresh |
WebDriverCommand::Status |
WebDriverCommand::SwitchToParentFrame |
WebDriverCommand::TakeElementScreenshot(_) |
WebDriverCommand::TakeScreenshot => {
None
},
- WebDriverCommand::AddCookie(ref x) => Some(x.to_json()),
- WebDriverCommand::ElementSendKeys(_, ref x) => Some(x.to_json()),
+ WebDriverCommand::AddCookie(ref x) => Some(x.into()),
+ WebDriverCommand::ElementSendKeys(_, ref x) => Some(x.into()),
WebDriverCommand::ExecuteAsyncScript(ref x) |
- WebDriverCommand::ExecuteScript(ref x) => Some(x.to_json()),
- WebDriverCommand::FindElementElement(_, ref x) => Some(x.to_json()),
- WebDriverCommand::FindElementElements(_, ref x) => Some(x.to_json()),
- WebDriverCommand::FindElement(ref x) => Some(x.to_json()),
- WebDriverCommand::FindElements(ref x) => Some(x.to_json()),
- WebDriverCommand::Get(ref x) => Some(x.to_json()),
- WebDriverCommand::PerformActions(ref x) => Some(x.to_json()),
- WebDriverCommand::SendAlertText(ref x) => Some(x.to_json()),
- WebDriverCommand::SetTimeouts(ref x) => Some(x.to_json()),
- WebDriverCommand::SetWindowRect(ref x) => Some(x.to_json()),
- WebDriverCommand::SwitchToFrame(ref x) => Some(x.to_json()),
- WebDriverCommand::SwitchToWindow(ref x) => Some(x.to_json()),
+ WebDriverCommand::ExecuteScript(ref x) => Some(x.into()),
+ WebDriverCommand::FindElementElement(_, ref x) => Some(x.into()),
+ WebDriverCommand::FindElementElements(_, ref x) => Some(x.into()),
+ WebDriverCommand::FindElement(ref x) => Some(x.into()),
+ WebDriverCommand::FindElements(ref x) => Some(x.into()),
+ WebDriverCommand::Get(ref x) => Some(x.into()),
+ WebDriverCommand::PerformActions(ref x) => Some(x.into()),
+ WebDriverCommand::SendAlertText(ref x) => Some(x.into()),
+ WebDriverCommand::SetTimeouts(ref x) => Some(x.into()),
+ WebDriverCommand::SetWindowRect(ref x) => Some(x.into()),
+ WebDriverCommand::SwitchToFrame(ref x) => Some(x.into()),
+ WebDriverCommand::SwitchToWindow(ref x) => Some(x.into()),
WebDriverCommand::Extension(ref x) => x.parameters_json(),
};
- let mut data = BTreeMap::new();
+ let mut data = Map::new();
if let Some(parameters) = parameters {
data.insert("parameters".to_string(), parameters);
}
- Json::Object(data)
+ Value::Object(data)
}
}
-pub trait Parameters: Sized {
- fn from_json(body: &Json) -> WebDriverResult<Self>;
-}
-
/// Wrapper around the two supported variants of new session paramters
///
/// The Spec variant is used for storing spec-compliant parameters whereas
/// the legacy variant is used to store desiredCapabilities/requiredCapabilities
/// parameters, and is intended to minimise breakage as we transition users to
/// the spec design.
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(untagged)]
+pub enum NewSessionParametersWrapper {
+ Spec(SpecNewSessionParametersWrapper),
+ Legacy(LegacyNewSessionParameters),
+}
+
#[derive(Debug, PartialEq)]
pub enum NewSessionParameters {
Spec(SpecNewSessionParameters),
Legacy(LegacyNewSessionParameters),
}
-impl Parameters for NewSessionParameters {
- fn from_json(body: &Json) -> WebDriverResult<NewSessionParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::UnknownError,
- "Message body was not an object");
- if data.get("capabilities").is_some() {
- Ok(NewSessionParameters::Spec(try!(SpecNewSessionParameters::from_json(body))))
- } else {
- Ok(NewSessionParameters::Legacy(try!(LegacyNewSessionParameters::from_json(body))))
+impl From<NewSessionParametersWrapper> for NewSessionParameters {
+ fn from(wrapper: NewSessionParametersWrapper) -> NewSessionParameters {
+ match wrapper {
+ NewSessionParametersWrapper::Spec(x) => NewSessionParameters::Spec(x.into()),
+ NewSessionParametersWrapper::Legacy(x) => NewSessionParameters::Legacy(x)
}
}
}
-impl ToJson for NewSessionParameters {
- fn to_json(&self) -> Json {
- match self {
- &NewSessionParameters::Spec(ref x) => x.to_json(),
- &NewSessionParameters::Legacy(ref x) => x.to_json()
+
+impl <'a> From<&'a NewSessionParameters> for Value {
+ fn from(params: &'a NewSessionParameters) -> Value {
+ match *params {
+ NewSessionParameters::Spec(ref x) => x.into(),
+ NewSessionParameters::Legacy(ref x) => x.into()
}
}
}
impl CapabilitiesMatching for NewSessionParameters {
fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
-> WebDriverResult<Option<Capabilities>> {
match self {
&NewSessionParameters::Spec(ref x) => x.match_browser(browser_capabilities),
&NewSessionParameters::Legacy(ref x) => x.match_browser(browser_capabilities)
}
}
}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GetParameters {
pub url: String
}
-impl Parameters for GetParameters {
- fn from_json(body: &Json) -> WebDriverResult<GetParameters> {
- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
- "Message body was not an object");
- let url = try_opt!(
- try_opt!(data.get("url"),
- ErrorStatus::InvalidArgument,
- "Missing 'url' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "'url' not a string");
- Ok(GetParameters {
- url: url.to_string()
- })
+impl<'a> From<&'a GetParameters> for Value {
+ fn from(params: &'a GetParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("url".to_string(), Value::String(params.url.clone()));
+ Value::Object(data)
}
}
-impl ToJson for GetParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("url".to_string(), self.url.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct TimeoutsParameters {
pub script: Option<u64>,
+ #[serde(rename="pageLoad")]
pub page_load: Option<u64>,
pub implicit: Option<u64>,
}
-impl Parameters for TimeoutsParameters {
- fn from_json(body: &Json) -> WebDriverResult<TimeoutsParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::UnknownError,
- "Message body was not an object");
-
- let script = match data.get("script") {
- Some(json) => {
- Some(try_opt!(json.as_u64(),
- ErrorStatus::InvalidArgument,
- "Script timeout duration was not a signed integer"))
- }
- None => None,
- };
-
- let page_load = match data.get("pageLoad") {
- Some(json) => {
- Some(try_opt!(json.as_u64(),
- ErrorStatus::InvalidArgument,
- "Page load timeout duration was not a signed integer"))
- }
- None => None,
- };
-
- let implicit = match data.get("implicit") {
- Some(json) => {
- Some(try_opt!(json.as_u64(),
- ErrorStatus::InvalidArgument,
- "Implicit timeout duration was not a signed integer"))
- }
- None => None,
- };
-
- Ok(TimeoutsParameters {
- script: script,
- page_load: page_load,
- implicit: implicit,
- })
- }
-}
-
-impl ToJson for TimeoutsParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- if let Some(ms) = self.script {
- data.insert("script".into(), ms.to_json());
+impl<'a> From<&'a TimeoutsParameters> for Value {
+ fn from(params: &'a TimeoutsParameters) -> Value {
+ let mut data = Map::new();
+ if let Some(ms) = params.script {
+ data.insert("script".into(), Value::Number(ms.into()));
}
- if let Some(ms) = self.page_load {
- data.insert("pageLoad".into(), ms.to_json());
+ if let Some(ms) = params.page_load {
+ data.insert("pageLoad".into(), Value::Number(ms.into()));
}
- if let Some(ms) = self.implicit {
- data.insert("implicit".into(), ms.to_json());
+ if let Some(ms) = params.implicit {
+ data.insert("implicit".into(), Value::Number(ms.into()));
}
- Json::Object(data)
+ Value::Object(data)
}
}
/// A top-level browsing context’s window rect is a dictionary of the
/// [`screenX`], [`screenY`], `width`, and `height` attributes of the
/// `WindowProxy`.
///
/// In some user agents the operating system’s window dimensions, including
/// decorations, are provided by the proprietary `window.outerWidth` and
/// `window.outerHeight` DOM properties.
///
/// [`screenX`]: https://w3c.github.io/webdriver/webdriver-spec.html#dfn-screenx
/// [`screenY`]: https://w3c.github.io/webdriver/webdriver-spec.html#dfn-screeny
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct WindowRectParameters {
- pub x: Nullable<i32>,
- pub y: Nullable<i32>,
- pub width: Nullable<i32>,
- pub height: Nullable<i32>,
+ pub x: Option<i32>,
+ pub y: Option<i32>,
+ pub width: Option<i32>,
+ pub height: Option<i32>,
}
-impl Parameters for WindowRectParameters {
- fn from_json(body: &Json) -> WebDriverResult<WindowRectParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument, "Message body was not an object");
-
- let x = match data.get("x") {
- Some(json) => try!(Nullable::from_json(json, |n| {
- let x = try_opt!(
- n.as_f64(),
- ErrorStatus::InvalidArgument,
- "'x' is not a number"
- ) as i64;
- if x < i32::min_value() as i64 || x > i32::max_value() as i64 {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "'x' is larger than i32",
- ));
- }
- Ok(x as i32)
- })),
- None => Nullable::Null,
- };
-
- let y = match data.get("y") {
- Some(json) => try!(Nullable::from_json(json, |n| {
- let y = try_opt!(
- n.as_f64(),
- ErrorStatus::InvalidArgument,
- "'y' is not a number"
- ) as i64;
- if y < i32::min_value() as i64 || y > i32::max_value() as i64 {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "'y' is larger than i32",
- ));
- }
- Ok(y as i32)
- })),
- None => Nullable::Null,
- };
-
- let width = match data.get("width") {
- Some(json) => try!(Nullable::from_json(json, |n| {
- let width = try_opt!(
- n.as_f64(),
- ErrorStatus::InvalidArgument,
- "'width' is not a number"
- ) as i64;
- if width < 0 || width > i32::max_value() as i64 {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "'width' is larger than i32",
- ));
- }
- Ok(width as i32)
- })),
- None => Nullable::Null,
- };
-
- let height = match data.get("height") {
- Some(json) => try!(Nullable::from_json(json, |n| {
- let height = try_opt!(
- n.as_f64(),
- ErrorStatus::InvalidArgument,
- "'height' is not a positive integer"
- ) as i64;
- if height < 0 || height > i32::max_value() as i64 {
- return Err(WebDriverError::new(
- ErrorStatus::InvalidArgument,
- "'height' is larger than i32",
- ));
- }
- Ok(height as i32)
- })),
- None => Nullable::Null,
- };
-
- Ok(WindowRectParameters { x, y, width, height })
+impl<'a> From<&'a WindowRectParameters> for Value {
+ fn from(params: &'a WindowRectParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("x".to_string(), params.x.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
+ data.insert("y".to_string(), params.y.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
+ data.insert("width".to_string(), params.width.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
+ data.insert("height".to_string(), params.height.map(|x| Value::Number(x.into())).unwrap_or(Value::Null));
+ Value::Object(data)
}
}
-impl ToJson for WindowRectParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("x".to_string(), self.x.to_json());
- data.insert("y".to_string(), self.y.to_json());
- data.insert("width".to_string(), self.width.to_json());
- data.insert("height".to_string(), self.height.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct SwitchToWindowParameters {
pub handle: String
}
-impl Parameters for SwitchToWindowParameters {
- fn from_json(body: &Json) -> WebDriverResult<SwitchToWindowParameters> {
- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
- "Message body was not an object");
- let handle = try_opt!(
- try_opt!(data.get("handle"),
- ErrorStatus::InvalidArgument,
- "Missing 'handle' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "'handle' not a string");
- return Ok(SwitchToWindowParameters {
- handle: handle.to_string()
- })
+impl<'a> From<&'a SwitchToWindowParameters> for Value {
+ fn from(params: &'a SwitchToWindowParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("handle".to_string(), params.handle.clone().into());
+ Value::Object(data)
}
}
-impl ToJson for SwitchToWindowParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("handle".to_string(), self.handle.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct LocatorParameters {
pub using: LocatorStrategy,
pub value: String
}
-impl Parameters for LocatorParameters {
- fn from_json(body: &Json) -> WebDriverResult<LocatorParameters> {
- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError,
- "Message body was not an object");
-
- let using = try!(LocatorStrategy::from_json(
- try_opt!(data.get("using"),
- ErrorStatus::InvalidArgument,
- "Missing 'using' parameter")));
-
- let value = try_opt!(
- try_opt!(data.get("value"),
- ErrorStatus::InvalidArgument,
- "Missing 'value' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Could not convert using to string").to_string();
-
- return Ok(LocatorParameters {
- using: using,
- value: value
- })
+impl<'a> From<&'a LocatorParameters> for Value {
+ fn from(params: &'a LocatorParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("using".to_string(), params.using.into());
+ data.insert("value".to_string(), params.value.clone().into());
+ Value::Object(data)
}
}
-impl ToJson for LocatorParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("using".to_string(), self.using.to_json());
- data.insert("value".to_string(), self.value.to_json());
- Json::Object(data)
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct SwitchToFrameParameters {
+ pub id: Option<FrameId>
+}
+
+impl<'a> From<&'a SwitchToFrameParameters> for Value {
+ fn from(params: &'a SwitchToFrameParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("id".to_string(), params.id.clone().map(|x| x.into()).unwrap_or(Value::Null));
+ Value::Object(data)
}
}
-#[derive(Debug, PartialEq)]
-pub struct SwitchToFrameParameters {
- pub id: FrameId
-}
-
-impl Parameters for SwitchToFrameParameters {
- fn from_json(body: &Json) -> WebDriverResult<SwitchToFrameParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::UnknownError,
- "Message body was not an object");
- let id = try!(FrameId::from_json(try_opt!(data.get("id"),
- ErrorStatus::UnknownError,
- "Missing 'id' parameter")));
-
- Ok(SwitchToFrameParameters {
- id: id
- })
- }
-}
-
-impl ToJson for SwitchToFrameParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("id".to_string(), self.id.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct SendKeysParameters {
pub text: String
}
-impl Parameters for SendKeysParameters {
- fn from_json(body: &Json) -> WebDriverResult<SendKeysParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Message body was not an object");
- let text = try_opt!(try_opt!(data.get("text"),
- ErrorStatus::InvalidArgument,
- "Missing 'text' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Could not convert 'text' to string");
-
- Ok(SendKeysParameters {
- text: text.into()
- })
- }
-}
-
-impl ToJson for SendKeysParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("value".to_string(), self.text.to_json());
- Json::Object(data)
+impl<'a> From<&'a SendKeysParameters> for Value {
+ fn from(params: &'a SendKeysParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("value".to_string(), params.text.clone().into());
+ Value::Object(data)
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct JavascriptCommandParameters {
pub script: String,
- pub args: Nullable<Vec<Json>>
+ pub args: Option<Vec<Value>>
}
-impl Parameters for JavascriptCommandParameters {
- fn from_json(body: &Json) -> WebDriverResult<JavascriptCommandParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Message body was not an object");
-
- let args_json = try_opt!(data.get("args"),
- ErrorStatus::InvalidArgument,
- "Missing args parameter");
-
- let args = try!(Nullable::from_json(
- args_json,
- |x| {
- Ok((try_opt!(x.as_array(),
- ErrorStatus::InvalidArgument,
- "Failed to convert args to Array")).clone())
- }));
-
- //TODO: Look for WebElements in args?
- let script = try_opt!(
- try_opt!(data.get("script"),
- ErrorStatus::InvalidArgument,
- "Missing script parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "Failed to convert script to String");
- Ok(JavascriptCommandParameters {
- script: script.to_string(),
- args: args.clone()
- })
+impl<'a> From<&'a JavascriptCommandParameters> for Value {
+ fn from(params: &'a JavascriptCommandParameters) -> Value {
+ let mut data = Map::new();
+ //TODO: Wrap script so that it becomes marionette-compatible
+ data.insert("script".to_string(), params.script.clone().into());
+ data.insert("args".to_string(), params.args.clone()
+ .map(|x| Value::Array(x))
+ .unwrap_or(Value::Null));
+ Value::Object(data)
}
}
-impl ToJson for JavascriptCommandParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- //TODO: Wrap script so that it becomes marionette-compatible
- data.insert("script".to_string(), self.script.to_json());
- data.insert("args".to_string(), self.args.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct GetNamedCookieParameters {
- pub name: Nullable<String>,
+ pub name: Option<String>
}
-impl Parameters for GetNamedCookieParameters {
- fn from_json(body: &Json) -> WebDriverResult<GetNamedCookieParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Message body was not an object");
- let name_json = try_opt!(data.get("name"),
- ErrorStatus::InvalidArgument,
- "Missing 'name' parameter");
- let name = try!(Nullable::from_json(name_json, |x| {
- Ok(try_opt!(x.as_string(),
- ErrorStatus::InvalidArgument,
- "Failed to convert name to string")
- .to_string())
- }));
- return Ok(GetNamedCookieParameters { name: name });
- }
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct AddCookieParametersWrapper {
+ cookie: AddCookieParameters
}
-impl ToJson for GetNamedCookieParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("name".to_string(), self.name.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(PartialEq, Serialize, Deserialize, Debug)]
pub struct AddCookieParameters {
pub name: String,
pub value: String,
- pub path: Nullable<String>,
- pub domain: Nullable<String>,
- pub expiry: Nullable<Date>,
+ pub path: Option<String>,
+ pub domain: Option<String>,
+ pub expiry: Option<Date>,
pub secure: bool,
pub httpOnly: bool
}
-impl Parameters for AddCookieParameters {
- fn from_json(body: &Json) -> WebDriverResult<AddCookieParameters> {
- if !body.is_object() {
- return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
- "Message body was not an object"));
- }
-
- let data = try_opt!(body.find("cookie").and_then(|x| x.as_object()),
- ErrorStatus::UnableToSetCookie,
- "Cookie parameter not found or not an object");
-
- let name = try_opt!(
- try_opt!(data.get("name"),
- ErrorStatus::InvalidArgument,
- "Missing 'name' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "'name' is not a string").to_string();
-
- let value = try_opt!(
- try_opt!(data.get("value"),
- ErrorStatus::InvalidArgument,
- "Missing 'value' parameter").as_string(),
- ErrorStatus::InvalidArgument,
- "'value' is not a string").to_string();
-
- let path = match data.get("path") {
- Some(path_json) => {
- try!(Nullable::from_json(
- path_json,
- |x| {
- Ok(try_opt!(x.as_string(),
- ErrorStatus::InvalidArgument,
- "Failed to convert path to String").to_string())
- }))
- },
- None => Nullable::Null
- };
-
- let domain = match data.get("domain") {
- Some(domain_json) => {
- try!(Nullable::from_json(
- domain_json,
- |x| {
- Ok(try_opt!(x.as_string(),
- ErrorStatus::InvalidArgument,
- "Failed to convert domain to String").to_string())
- }))
- },
- None => Nullable::Null
- };
-
- let expiry = match data.get("expiry") {
- Some(expiry_json) => {
- try!(Nullable::from_json(
- expiry_json,
- |x| {
- Ok(Date::new(try_opt!(x.as_u64(),
- ErrorStatus::InvalidArgument,
- "Failed to convert expiry to Date")))
- }))
- },
- None => Nullable::Null
- };
-
- let secure = match data.get("secure") {
- Some(x) => try_opt!(x.as_boolean(),
- ErrorStatus::InvalidArgument,
- "Failed to convert secure to boolean"),
- None => false
- };
-
- let http_only = match data.get("httpOnly") {
- Some(x) => try_opt!(x.as_boolean(),
- ErrorStatus::InvalidArgument,
- "Failed to convert httpOnly to boolean"),
- None => false
- };
-
- return Ok(AddCookieParameters {
- name: name,
- value: value,
- path: path,
- domain: domain,
- expiry: expiry,
- secure: secure,
- httpOnly: http_only
- })
+impl<'a> From<&'a AddCookieParameters> for Value {
+ fn from(params: &'a AddCookieParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("name".to_string(), params.name.clone().into());
+ data.insert("value".to_string(), params.value.clone().into());
+ data.insert("path".to_string(), params.path.clone().map(|x| x.into()).unwrap_or(Value::Null));
+ data.insert("domain".to_string(), params.domain.clone().map(|x| x.into()).unwrap_or(Value::Null));
+ data.insert("expiry".to_string(), params.expiry.clone().map(|x| x.into()).unwrap_or(Value::Null));
+ data.insert("secure".to_string(), params.secure.into());
+ data.insert("httpOnly".to_string(), params.httpOnly.into());
+ Value::Object(data)
}
}
-impl ToJson for AddCookieParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("name".to_string(), self.name.to_json());
- data.insert("value".to_string(), self.value.to_json());
- data.insert("path".to_string(), self.path.to_json());
- data.insert("domain".to_string(), self.domain.to_json());
- data.insert("expiry".to_string(), self.expiry.to_json());
- data.insert("secure".to_string(), self.secure.to_json());
- data.insert("httpOnly".to_string(), self.httpOnly.to_json());
- Json::Object(data)
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
+pub struct TakeScreenshotParameters {
+ pub element: Option<WebElement>
+}
+
+impl<'a> From<&'a TakeScreenshotParameters> for Value {
+ fn from(params: &'a TakeScreenshotParameters) -> Value {
+ let mut data = Map::new();
+ data.insert("element".to_string(), params.element.clone().map(|x| (&x).into()).unwrap_or(Value::Null));
+ Value::Object(data)
}
}
-#[derive(Debug, PartialEq)]
-pub struct TakeScreenshotParameters {
- pub element: Nullable<WebElement>
-}
-
-impl Parameters for TakeScreenshotParameters {
- fn from_json(body: &Json) -> WebDriverResult<TakeScreenshotParameters> {
- let data = try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Message body was not an object");
- let element = match data.get("element") {
- Some(element_json) => try!(Nullable::from_json(
- element_json,
- |x| {
- Ok(try!(WebElement::from_json(x)))
- })),
- None => Nullable::Null
- };
-
- return Ok(TakeScreenshotParameters {
- element: element
- })
- }
-}
-
-impl ToJson for TakeScreenshotParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("element".to_string(), self.element.to_json());
- Json::Object(data)
- }
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct ActionsParameters {
pub actions: Vec<ActionSequence>
}
-impl Parameters for ActionsParameters {
- fn from_json(body: &Json) -> WebDriverResult<ActionsParameters> {
- try_opt!(body.as_object(),
- ErrorStatus::InvalidArgument,
- "Message body was not an object");
- let actions = try_opt!(
- try_opt!(body.find("actions"),
- ErrorStatus::InvalidArgument,
- "No actions parameter found").as_array(),
- ErrorStatus::InvalidArgument,
- "Parameter 'actions' was not an array");
-
- let mut result = Vec::with_capacity(actions.len());
- for chain in actions.iter() {
- result.push(try!(ActionSequence::from_json(chain)));
- }
- Ok(ActionsParameters {
- actions: result
- })
- }
-}
-
-impl ToJson for ActionsParameters {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
+impl<'a> From<&'a ActionsParameters> for Value {
+ fn from(params: &'a ActionsParameters) -> Value {
+ let mut data = Map::new();
data.insert("actions".to_owned(),
- self.actions.iter().map(|x| x.to_json()).collect::<Vec<Json>>().to_json());
- Json::Object(data)
+ params.actions.iter().map(|x| x.into()).collect::<Vec<Value>>().into());
+ Value::Object(data)
}
}
#[cfg(test)]
mod tests {
- use rustc_serialize::json::Json;
- use super::{Nullable, Parameters, WindowRectParameters};
+ use serde_json;
+ use super::WindowRectParameters;
#[test]
fn test_window_rect() {
let expected = WindowRectParameters {
- x: Nullable::Value(0i32),
- y: Nullable::Value(1i32),
- width: Nullable::Value(2i32),
- height: Nullable::Value(3i32),
+ x: Some(0i32),
+ y: Some(1i32),
+ width: Some(2i32),
+ height: Some(3i32),
};
- let actual = Json::from_str(r#"{"x": 0, "y": 1, "width": 2, "height": 3}"#).unwrap();
- assert_eq!(expected, Parameters::from_json(&actual).unwrap());
+
+ let data = r#"{"x": 0, "y": 1, "width": 2, "height": 3}"#;
+ let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
+ assert_eq!(expected, actual);
}
#[test]
fn test_window_rect_nullable() {
let expected = WindowRectParameters {
- x: Nullable::Value(0i32),
- y: Nullable::Null,
- width: Nullable::Value(2i32),
- height: Nullable::Null,
+ x: Some(0i32),
+ y: None,
+ width: Some(2i32),
+ height: None,
};
- let actual = Json::from_str(r#"{"x": 0, "y": null, "width": 2, "height": null}"#).unwrap();
- assert_eq!(expected, Parameters::from_json(&actual).unwrap());
+
+ let data = r#"{"x": 0, "y": null, "width": 2, "height": null}"#;
+ let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
+ assert_eq!(expected, actual);
}
#[test]
fn test_window_rect_missing_fields() {
let expected = WindowRectParameters {
- x: Nullable::Value(0i32),
- y: Nullable::Null,
- width: Nullable::Value(2i32),
- height: Nullable::Null,
+ x: Some(0i32),
+ y: None,
+ width: Some(2i32),
+ height: None,
};
- let actual = Json::from_str(r#"{"x": 0, "width": 2}"#).unwrap();
- assert_eq!(expected, Parameters::from_json(&actual).unwrap());
+
+ let data = r#"{"x": 0, "width": 2}"#;
+ let actual: WindowRectParameters = serde_json::from_str(&data).unwrap();
+ assert_eq!(expected, actual);
}
#[test]
fn test_window_rect_floats() {
- let expected = WindowRectParameters {
- x: Nullable::Value(1i32),
- y: Nullable::Value(2i32),
- width: Nullable::Value(3i32),
- height: Nullable::Value(4i32),
- };
- let actual = Json::from_str(r#"{"x": 1.1, "y": 2.2, "width": 3.3, "height": 4.4}"#).unwrap();
- assert_eq!(expected, Parameters::from_json(&actual).unwrap());
+ let data = r#"{"x": 1.1, "y": 2.2, "width": 3.3, "height": 4.4}"#;
+ assert!(serde_json::from_str::<WindowRectParameters>(&data).is_err());
}
}
--- a/testing/webdriver/src/common.rs
+++ b/testing/webdriver/src/common.rs
@@ -1,222 +1,127 @@
-use rustc_serialize::{Encodable, Encoder};
-use rustc_serialize::json::{Json, ToJson};
-use std::collections::BTreeMap;
+use serde_json::{Value, Map};
+use std::convert::From;
use error::{WebDriverResult, WebDriverError, ErrorStatus};
pub static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";
-#[derive(Clone, Debug, PartialEq, RustcEncodable)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Date(pub u64);
impl Date {
pub fn new(timestamp: u64) -> Date {
Date(timestamp)
}
}
-impl ToJson for Date {
- fn to_json(&self) -> Json {
- let &Date(x) = self;
- x.to_json()
- }
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum Nullable<T: ToJson> {
- Value(T),
- Null
-}
-
-impl<T: ToJson> Nullable<T> {
- pub fn is_null(&self) -> bool {
- match *self {
- Nullable::Value(_) => false,
- Nullable::Null => true
- }
- }
-
- pub fn is_value(&self) -> bool {
- match *self {
- Nullable::Value(_) => true,
- Nullable::Null => false
- }
- }
-
- pub fn map<F, U: ToJson>(self, f: F) -> Nullable<U>
- where F: FnOnce(T) -> U {
- match self {
- Nullable::Value(val) => Nullable::Value(f(val)),
- Nullable::Null => Nullable::Null
- }
+impl From<Date> for Value {
+ fn from(date: Date) -> Value {
+ let Date(x) = date;
+ x.into()
}
}
-impl<T: ToJson> Nullable<T> {
- //This is not very pretty
- pub fn from_json<F: FnOnce(&Json) -> WebDriverResult<T>>(value: &Json, f: F) -> WebDriverResult<Nullable<T>> {
- if value.is_null() {
- Ok(Nullable::Null)
- } else {
- Ok(Nullable::Value(try!(f(value))))
- }
- }
-}
-
-impl<T: ToJson> ToJson for Nullable<T> {
- fn to_json(&self) -> Json {
- match *self {
- Nullable::Value(ref x) => x.to_json(),
- Nullable::Null => Json::Null
- }
- }
-}
-
-impl<T: ToJson> Encodable for Nullable<T> {
- fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- match *self {
- Nullable::Value(ref x) => x.to_json().encode(s),
- Nullable::Null => s.emit_option_none()
- }
- }
-}
-
-impl<T: ToJson> Into<Option<T>> for Nullable<T> {
- fn into(self) -> Option<T> {
- match self {
- Nullable::Value(val) => Some(val),
- Nullable::Null => None
- }
- }
-}
-
-impl<T: ToJson> From<Option<T>> for Nullable<T> {
- fn from(option: Option<T>) -> Nullable<T> {
- match option {
- Some(val) => Nullable::Value(val),
- None => Nullable::Null,
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct WebElement {
+ #[serde(rename="element-6066-11e4-a52e-4f735466cecf")]
pub id: String
}
impl WebElement {
pub fn new(id: String) -> WebElement {
WebElement {
id: id
}
}
- pub fn from_json(data: &Json) -> WebDriverResult<WebElement> {
+ pub fn from_json(data: &Value) -> WebDriverResult<WebElement> {
let object = try_opt!(data.as_object(),
ErrorStatus::InvalidArgument,
"Could not convert webelement to object");
let id_value = try_opt!(object.get(ELEMENT_KEY),
ErrorStatus::InvalidArgument,
"Could not find webelement key");
- let id = try_opt!(id_value.as_string(),
+ let id = try_opt!(id_value.as_str(),
ErrorStatus::InvalidArgument,
"Could not convert web element to string").to_string();
Ok(WebElement::new(id))
}
}
-impl ToJson for WebElement {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert(ELEMENT_KEY.to_string(), self.id.to_json());
- Json::Object(data)
+impl <'a> From<&'a WebElement> for Value {
+ fn from(elem: &'a WebElement) -> Value {
+ let mut data = Map::new();
+ data.insert(ELEMENT_KEY.to_string(), elem.id.clone().into());
+ Value::Object(data)
}
}
impl <T> From<T> for WebElement
where T: Into<String> {
fn from(data: T) -> WebElement {
WebElement::new(data.into())
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum FrameId {
Short(u16),
- Element(WebElement),
- Null
+ Element(WebElement)
}
-impl FrameId {
- pub fn from_json(data: &Json) -> WebDriverResult<FrameId> {
- match data {
- &Json::U64(x) => {
- if x > u16::max_value() as u64 || x < u16::min_value() as u64 {
- return Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
- "frame id out of range"))
- };
- Ok(FrameId::Short(x as u16))
- },
- &Json::Null => Ok(FrameId::Null),
- &Json::Object(_) => Ok(FrameId::Element(
- try!(WebElement::from_json(data)))),
- _ => Err(WebDriverError::new(ErrorStatus::NoSuchFrame,
- "frame id has unexpected type"))
- }
- }
-}
-
-impl ToJson for FrameId {
- fn to_json(&self) -> Json {
- match *self {
+impl From<FrameId> for Value {
+ fn from(frame_id: FrameId) -> Value {
+ match frame_id {
FrameId::Short(x) => {
- Json::U64(x as u64)
+ Value::Number(x.into())
},
FrameId::Element(ref x) => {
- Json::String(x.id.clone())
- },
- FrameId::Null => {
- Json::Null
+ Value::String(x.id.clone())
}
}
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum LocatorStrategy {
+ #[serde(rename = "css selector")]
CSSSelector,
+ #[serde(rename = "link text")]
LinkText,
+ #[serde(rename = "partial link text")]
PartialLinkText,
+ #[serde(rename = "tag name")]
TagName,
+ #[serde(rename = "xpath")]
XPath,
}
impl LocatorStrategy {
- pub fn from_json(body: &Json) -> WebDriverResult<LocatorStrategy> {
- match try_opt!(body.as_string(),
+ pub fn from_json(body: &Value) -> WebDriverResult<LocatorStrategy> {
+ match try_opt!(body.as_str(),
ErrorStatus::InvalidArgument,
"Expected locator strategy as string") {
"css selector" => Ok(LocatorStrategy::CSSSelector),
"link text" => Ok(LocatorStrategy::LinkText),
"partial link text" => Ok(LocatorStrategy::PartialLinkText),
"tag name" => Ok(LocatorStrategy::TagName),
"xpath" => Ok(LocatorStrategy::XPath),
x => Err(WebDriverError::new(ErrorStatus::InvalidArgument,
format!("Unknown locator strategy {}", x)))
}
}
}
-impl ToJson for LocatorStrategy {
- fn to_json(&self) -> Json {
- Json::String(match *self {
+impl From<LocatorStrategy> for Value {
+ fn from(strategy: LocatorStrategy) -> Value {
+ match strategy {
LocatorStrategy::CSSSelector => "css selector",
LocatorStrategy::LinkText => "link text",
LocatorStrategy::PartialLinkText => "partial link text",
LocatorStrategy::TagName => "tag name",
LocatorStrategy::XPath => "xpath"
- }.to_string())
+ }.into()
}
}
--- a/testing/webdriver/src/error.rs
+++ b/testing/webdriver/src/error.rs
@@ -1,17 +1,16 @@
use hyper::status::StatusCode;
-use rustc_serialize::base64::FromBase64Error;
-use rustc_serialize::json::{DecoderError, Json, ParserError, ToJson};
+use base64::DecodeError;
use std::borrow::Cow;
-use std::collections::BTreeMap;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io;
+use serde_json::{self, Value, Error as SerdeError, Map};
#[derive(Debug, PartialEq)]
pub enum ErrorStatus {
/// The [`ElementClick`] command could not be completed because the
/// [element] receiving the events is obscuring the element that was
/// requested clicked.
///
/// [`ElementClick`]:
@@ -288,30 +287,30 @@ impl WebDriverError {
self.error.error_code()
}
pub fn http_status(&self) -> StatusCode {
self.error.http_status()
}
pub fn to_json_string(&self) -> String {
- self.to_json().to_string()
+ serde_json::to_string(&Value::from(self)).unwrap()
}
}
-impl ToJson for WebDriverError {
- fn to_json(&self) -> Json {
- let mut data = BTreeMap::new();
- data.insert("error".into(), self.error_code().to_json());
- data.insert("message".into(), self.message.to_json());
- data.insert("stacktrace".into(), self.stack.to_json());
-
- let mut wrapper = BTreeMap::new();
- wrapper.insert("value".into(), Json::Object(data));
- Json::Object(wrapper)
+impl <'a> From<&'a WebDriverError> for Value {
+ fn from(err: &'a WebDriverError) -> Value {
+ let mut data = Map::new();
+ data.insert("error".into(), err.error_code().into());
+ data.insert("message".into(), err.message.clone().into());
+ data.insert("stacktrace".into(),
+ format!("{:?}", err.stack).into());
+ let mut wrapper = Map::new();
+ wrapper.insert("value".into(), Value::Object(data));
+ Value::Object(wrapper)
}
}
impl Error for WebDriverError {
fn description(&self) -> &str {
self.error_code()
}
@@ -321,36 +320,30 @@ impl Error for WebDriverError {
}
impl fmt::Display for WebDriverError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.message.fmt(f)
}
}
-impl From<ParserError> for WebDriverError {
- fn from(err: ParserError) -> WebDriverError {
+impl From<SerdeError> for WebDriverError {
+ fn from(err: SerdeError) -> WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
}
}
impl From<io::Error> for WebDriverError {
fn from(err: io::Error) -> WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
}
}
-impl From<DecoderError> for WebDriverError {
- fn from(err: DecoderError) -> WebDriverError {
- WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
- }
-}
-
-impl From<FromBase64Error> for WebDriverError {
- fn from(err: FromBase64Error) -> WebDriverError {
+impl From<DecodeError> for WebDriverError {
+ fn from(err: DecodeError) -> WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
}
}
impl From<Box<Error>> for WebDriverError {
fn from(err: Box<Error>) -> WebDriverError {
WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
}
--- a/testing/webdriver/src/httpapi.rs
+++ b/testing/webdriver/src/httpapi.rs
@@ -1,13 +1,13 @@
use regex::{Regex, Captures};
-use rustc_serialize::json::Json;
use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};
+use serde_json::Value;
use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand,
VoidWebDriverExtensionCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
fn standard_routes<U:WebDriverExtensionRoute>() -> Vec<(Method, &'static str, Route<U>)> {
return vec![(Post, "/session", Route::NewSession),
(Delete, "/session/{sessionId}", Route::DeleteSession),
@@ -134,26 +134,26 @@ pub enum Route<U:WebDriverExtensionRoute
TakeElementScreenshot,
Status,
Extension(U),
}
pub trait WebDriverExtensionRoute : Clone + Send + PartialEq {
type Command: WebDriverExtensionCommand + 'static;
- fn command(&self, &Captures, &Json) -> WebDriverResult<WebDriverCommand<Self::Command>>;
+ fn command(&self, &Captures, &Value) -> WebDriverResult<WebDriverCommand<Self::Command>>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct VoidWebDriverExtensionRoute;
impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute {
type Command = VoidWebDriverExtensionCommand;
- fn command(&self, _:&Captures, _:&Json) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
+ fn command(&self, _:&Captures, _:&Value) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
panic!("No extensions implemented");
}
}
#[derive(Clone, Debug)]
struct RequestMatcher<U: WebDriverExtensionRoute> {
method: Method,
path_regexp: Regex,
--- a/testing/webdriver/src/lib.rs
+++ b/testing/webdriver/src/lib.rs
@@ -1,44 +1,26 @@
#![allow(non_snake_case)]
+extern crate base64;
#[macro_use]
extern crate log;
-extern crate rustc_serialize;
extern crate hyper;
extern crate regex;
extern crate cookie;
+extern crate serde;
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_json;
extern crate time;
extern crate url;
extern crate unicode_segmentation;
#[macro_use] pub mod macros;
pub mod actions;
pub mod httpapi;
pub mod capabilities;
pub mod command;
pub mod common;
pub mod error;
pub mod server;
pub mod response;
-#[cfg(test)]
-mod nullable_tests {
- use super::common::Nullable;
-
- #[test]
- fn test_nullable_map() {
- let mut test = Nullable::Value(21);
-
- assert_eq!(test.map(|x| x << 1), Nullable::Value(42));
-
- test = Nullable::Null;
-
- assert_eq!(test.map(|x| x << 1), Nullable::Null);
- }
-
- #[test]
- fn test_nullable_into() {
- let test: Option<i32> = Nullable::Value(42).into();
-
- assert_eq!(test, Some(42));
- }
-}
--- a/testing/webdriver/src/response.rs
+++ b/testing/webdriver/src/response.rs
@@ -1,12 +1,12 @@
-use common::{Date, Nullable};
+use common::Date;
use cookie;
-use rustc_serialize::json::{self, Json, ToJson};
-use std::collections::BTreeMap;
+use serde_json::{self, Value};
+use std::convert::From;
use time;
#[derive(Debug)]
pub enum WebDriverResponse {
CloseWindow(CloseWindowResponse),
Cookie(CookieResponse),
Cookies(CookiesResponse),
DeleteSession,
@@ -18,107 +18,107 @@ pub enum WebDriverResponse {
WindowRect(WindowRectResponse),
}
impl WebDriverResponse {
pub fn to_json_string(self) -> String {
use response::WebDriverResponse::*;
let obj = match self {
- CloseWindow(ref x) => json::encode(&x.to_json()),
- Cookie(ref x) => json::encode(x),
- Cookies(ref x) => json::encode(x),
+ CloseWindow(ref x) => serde_json::to_string(&Value::from(x)),
+ Cookie(ref x) => serde_json::to_string(x),
+ Cookies(ref x) => serde_json::to_string(x),
DeleteSession => Ok("{}".to_string()),
- ElementRect(ref x) => json::encode(x),
- Generic(ref x) => json::encode(x),
- NewSession(ref x) => json::encode(x),
- Timeouts(ref x) => json::encode(x),
+ ElementRect(ref x) => serde_json::to_string(x),
+ Generic(ref x) => serde_json::to_string(x),
+ NewSession(ref x) => serde_json::to_string(x),
+ Timeouts(ref x) => serde_json::to_string(x),
Void => Ok("{}".to_string()),
- WindowRect(ref x) => json::encode(&x.to_json()),
+ WindowRect(ref x) => serde_json::to_string(x),
}.unwrap();
match self {
Generic(_) | Cookie(_) | Cookies(_) => obj,
_ => {
let mut data = String::with_capacity(11 + obj.len());
data.push_str("{\"value\": ");
data.push_str(&*obj);
data.push_str("}");
data
}
}
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct CloseWindowResponse {
pub window_handles: Vec<String>,
}
impl CloseWindowResponse {
pub fn new(handles: Vec<String>) -> CloseWindowResponse {
CloseWindowResponse { window_handles: handles }
}
}
-impl ToJson for CloseWindowResponse {
- fn to_json(&self) -> Json {
- Json::Array(self.window_handles
+impl <'a> From<&'a CloseWindowResponse> for Value {
+ fn from(resp: &'a CloseWindowResponse) -> Value {
+ Value::Array(resp.window_handles
.iter()
- .map(|x| Json::String(x.clone()))
- .collect::<Vec<Json>>())
+ .map(|x| Value::String(x.clone()))
+ .collect::<Vec<Value>>())
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct NewSessionResponse {
pub sessionId: String,
- pub capabilities: json::Json
+ pub capabilities: Value
}
impl NewSessionResponse {
- pub fn new(session_id: String, capabilities: json::Json) -> NewSessionResponse {
+ pub fn new(session_id: String, capabilities: Value) -> NewSessionResponse {
NewSessionResponse {
capabilities: capabilities,
sessionId: session_id
}
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct TimeoutsResponse {
pub script: u64,
pub pageLoad: u64,
pub implicit: u64,
}
impl TimeoutsResponse {
pub fn new(script: u64, page_load: u64, implicit: u64) -> TimeoutsResponse {
TimeoutsResponse {
script: script,
pageLoad: page_load,
implicit: implicit,
}
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct ValueResponse {
- pub value: json::Json
+ pub value: Value
}
impl ValueResponse {
- pub fn new(value: json::Json) -> ValueResponse {
+ pub fn new(value: Value) -> ValueResponse {
ValueResponse {
value: value
}
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct ElementRectResponse {
/// X axis position of the top-left corner of the element relative
// to the current browsing context’s document element in CSS reference
// pixels.
pub x: f64,
/// Y axis position of the top-left corner of the element relative
// to the current browsing context’s document element in CSS reference
@@ -133,17 +133,17 @@ pub struct ElementRectResponse {
/// Width of the element’s [bounding rectangle] in CSS reference
/// pixels.
///
/// [bounding rectangle]: https://drafts.fxtf.org/geometry/#rectangle
pub height: f64,
}
-#[derive(Debug)]
+#[derive(Debug, Serialize)]
pub struct WindowRectResponse {
/// `WindowProxy`’s [screenX] attribute.
///
/// [screenX]: https://drafts.csswg.org/cssom-view/#dom-window-screenx
pub x: i32,
/// `WindowProxy`’s [screenY] attribute.
///
@@ -156,121 +156,124 @@ pub struct WindowRectResponse {
pub width: i32,
/// Height of the top-level browsing context’s outer dimensions, including
/// any browser chrome and externally drawn window decorations in CSS
/// reference pixels.
pub height: i32,
}
-impl ToJson for WindowRectResponse {
- fn to_json(&self) -> Json {
- let mut body = BTreeMap::new();
- body.insert("x".to_owned(), self.x.to_json());
- body.insert("y".to_owned(), self.y.to_json());
- body.insert("width".to_owned(), self.width.to_json());
- body.insert("height".to_owned(), self.height.to_json());
- Json::Object(body)
- }
-}
-
-#[derive(Clone, Debug, PartialEq, RustcEncodable)]
+#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Cookie {
pub name: String,
pub value: String,
- pub path: Nullable<String>,
- pub domain: Nullable<String>,
- pub expiry: Nullable<Date>,
+ pub path: Option<String>,
+ pub domain: Option<String>,
+ pub expiry: Option<Date>,
pub secure: bool,
pub httpOnly: bool,
}
+impl Cookie {
+ pub fn new(name: String, value: String, path: Option<String>, domain: Option<String>,
+ expiry: Option<Date>, secure: bool, http_only: bool) -> Cookie {
+ Cookie {
+ name: name,
+ value: value,
+ path: path,
+ domain: domain,
+ expiry: expiry,
+ secure: secure,
+ httpOnly: http_only
+ }
+ }
+}
+
impl Into<cookie::Cookie<'static>> for Cookie {
fn into(self) -> cookie::Cookie<'static> {
let cookie = cookie::Cookie::build(self.name, self.value)
.secure(self.secure)
.http_only(self.httpOnly);
let cookie = match self.domain {
- Nullable::Value(domain) => cookie.domain(domain),
- Nullable::Null => cookie,
+ Some(domain) => cookie.domain(domain),
+ None => cookie,
};
let cookie = match self.path {
- Nullable::Value(path) => cookie.path(path),
- Nullable::Null => cookie,
+ Some(path) => cookie.path(path),
+ None => cookie,
};
let cookie = match self.expiry {
- Nullable::Value(Date(expiry)) => {
+ Some(Date(expiry)) => {
cookie.expires(time::at(time::Timespec::new(expiry as i64, 0)))
- }
- Nullable::Null => cookie,
+ },
+ None => cookie,
};
cookie.finish()
}
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct CookieResponse {
pub value: Cookie,
}
-#[derive(Debug, RustcEncodable)]
+#[derive(Debug, Serialize)]
pub struct CookiesResponse {
pub value: Vec<Cookie>,
}
#[cfg(test)]
mod tests {
use super::{CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, ElementRectResponse,
- NewSessionResponse, Nullable, TimeoutsResponse, ValueResponse, WebDriverResponse,
+ NewSessionResponse, TimeoutsResponse, ValueResponse, WebDriverResponse,
WindowRectResponse};
- use rustc_serialize::json::Json;
- use std::collections::BTreeMap;
+ use serde_json::{self, Map, Value};
fn test(resp: WebDriverResponse, expected_str: &str) {
let data = resp.to_json_string();
- let actual = Json::from_str(&*data).unwrap();
- let expected = Json::from_str(expected_str).unwrap();
+ let actual: Value = serde_json::from_str(&*data).unwrap();
+ let expected: Value = serde_json::from_str(expected_str).unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_close_window() {
let resp = WebDriverResponse::CloseWindow(
CloseWindowResponse::new(vec!["test".into()]));
let expected = r#"{"value": ["test"]}"#;
test(resp, expected);
}
#[test]
fn test_cookie() {
let cookie = Cookie {
name: "name".into(),
value: "value".into(),
- path: Nullable::Value("/".into()),
- domain: Nullable::Null,
- expiry: Nullable::Null,
+ path: Some("/".into()),
+ domain: None,
+ expiry: None,
secure: true,
httpOnly: false,
};
let resp = WebDriverResponse::Cookie(CookieResponse { value: cookie });
let expected = r#"{"value": {"name": "name", "expiry": null, "value": "value",
"path": "/", "domain": null, "secure": true, "httpOnly": false}}"#;
test(resp, expected);
}
#[test]
fn test_cookies() {
let resp = WebDriverResponse::Cookies(CookiesResponse {
value: vec![
Cookie {
name: "name".into(),
value: "value".into(),
- path: Nullable::Value("/".into()),
- domain: Nullable::Null,
- expiry: Nullable::Null,
+ path: Some("/".into()),
+ domain: None,
+ expiry: None,
secure: true,
httpOnly: false,
}
]});
let expected = r#"{"value": [{"name": "name", "value": "value", "path": "/",
"domain": null, "expiry": null, "secure": true, "httpOnly": false}]}"#;
test(resp, expected);
}
@@ -300,31 +303,31 @@ mod tests {
let expected = r#"{"value": {"x": 0, "y": 1, "width": 2, "height": 3}}"#;
test(resp, expected);
}
#[test]
fn test_new_session() {
let resp = WebDriverResponse::NewSession(
NewSessionResponse::new("test".into(),
- Json::Object(BTreeMap::new())));
+ Value::Object(Map::new())));
let expected = r#"{"value": {"sessionId": "test", "capabilities": {}}}"#;
test(resp, expected);
}
#[test]
fn test_timeouts() {
let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new(
1, 2, 3));
let expected = r#"{"value": {"script": 1, "pageLoad": 2, "implicit": 3}}"#;
test(resp, expected);
}
#[test]
fn test_value() {
- let mut value = BTreeMap::new();
- value.insert("example".into(), Json::Array(vec![Json::String("test".into())]));
+ let mut value = Map::new();
+ value.insert("example".into(), Value::Array(vec![Value::String("test".into())]));
let resp = WebDriverResponse::Generic(ValueResponse::new(
- Json::Object(value)));
+ Value::Object(value)));
let expected = r#"{"value": {"example": ["test"]}}"#;
test(resp, expected);
}
}