Bug 1396823 - Use unicode-segmentation to iterate graphemes instead of chars r=ato
MozReview-Commit-ID: 8QsOmtXDnGI
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2037,16 +2037,17 @@ name = "webdriver"
version = "0.34.0"
dependencies = [
"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)",
"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"
dependencies = [
"app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/testing/web-platform/tests/webdriver/tests/actions/special_keys.py
+++ b/testing/web-platform/tests/webdriver/tests/actions/special_keys.py
@@ -1,15 +1,15 @@
# META: timeout=long
import pytest
import time
from tests.actions.support.keys import ALL_EVENTS, Keys
from tests.actions.support.refine import filter_dict, get_keys, get_events
-
+from webdriver import error
@pytest.mark.parametrize("name,expected", ALL_EVENTS.items())
def test_webdriver_special_key_sends_keydown(session,
key_reporter,
key_chain,
name,
expected):
if name.startswith("F"):
@@ -38,8 +38,42 @@ def test_webdriver_special_key_sends_key
del expected["code"]
assert first_event == expected
# only printable characters should be recorded in input field
entered_keys = get_keys(key_reporter)
if len(expected["key"]) == 1:
assert entered_keys == expected["key"]
else:
assert len(entered_keys) == 0
+
+
+@pytest.mark.parametrize("value", [
+ (u"f"),
+ (u"\u0BA8\u0BBF"),
+ (u"\u1100\u1161\u11A8"),
+])
+def test_multiple_codepoint_keys_behave_correctly(session,
+ key_reporter,
+ key_chain,
+ value):
+ key_chain \
+ .key_down(value) \
+ .key_up(value) \
+ .perform()
+
+ assert get_keys(key_reporter) == value
+
+
+@pytest.mark.parametrize("value", [
+ (u"fa"),
+ (u"\u0BA8\u0BBFb"),
+ (u"\u0BA8\u0BBF\u0BA8"),
+ (u"\u1100\u1161\u11A8c")
+])
+def test_invalid_multiple_codepoint_keys_fail(session,
+ key_reporter,
+ key_chain,
+ value):
+ with pytest.raises(error.InvalidArgumentException):
+ key_chain \
+ .key_down(value) \
+ .key_up(value) \
+ .perform()
\ No newline at end of file
--- a/testing/webdriver/Cargo.toml
+++ b/testing/webdriver/Cargo.toml
@@ -12,8 +12,9 @@ license = "MPL-2.0"
[dependencies]
cookie = { version = "0.10", default-features = false }
hyper = "0.10"
log = "0.4"
regex = "0.2"
rustc-serialize = "0.3"
time = "0.1"
url = "1"
+unicode-segmentation = "1.1.0"
\ No newline at end of file
--- a/testing/webdriver/src/actions.rs
+++ b/testing/webdriver/src/actions.rs
@@ -1,12 +1,13 @@
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 std::default::Default;
#[derive(Debug, PartialEq)]
pub struct ActionSequence {
pub id: Nullable<String>,
pub actions: ActionsType
}
@@ -363,36 +364,36 @@ 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(),
}
}
}
-fn validate_key_value(value_str: &str) -> WebDriverResult<char> {
- let mut chars = value_str.chars();
- let value = if let Some(c) = chars.next() {
- c
+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 chars.next().is_some() {
+ if graphemes.next().is_some() {
return Err(WebDriverError::new(
ErrorStatus::InvalidArgument,
- "Parameter 'value' contained multiple characters"))
+ "Parameter 'value' contained multiple graphemes"))
};
- Ok(value)
+ Ok(value.to_string())
}
#[derive(Debug, PartialEq)]
pub struct KeyUpAction {
- pub value: char
+ 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(),
@@ -414,17 +415,17 @@ impl ToJson for KeyUpAction {
data.insert("value".to_string(),
self.value.to_string().to_json());
Json::Object(data)
}
}
#[derive(Debug, PartialEq)]
pub struct KeyDownAction {
- pub value: char
+ 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(),
--- a/testing/webdriver/src/lib.rs
+++ b/testing/webdriver/src/lib.rs
@@ -3,16 +3,17 @@
#[macro_use]
extern crate log;
extern crate rustc_serialize;
extern crate hyper;
extern crate regex;
extern crate cookie;
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;