Auto merge of #20051 - jonleighton:prevent-invalid-selections, r=jdm

Disallow mutating the internals of TextInput

The TextInput::assert_ok_selection() method is meant to ensure that we
are not getting into a state where a selection refers to a location in
the control's contents which doesn't exist.

However, before this change we could have a situation where the
internals of the TextInput are changed by another part of the code,
without using its public API. This could lead to us having an invalid
selection.

I did manage to trigger such a situation (see the test added in this
commit) although it is quite contrived. There may be others that I
didn't think of, and it's also possible that future changes could
introduce new cases. (Including ones which trigger panics, if indexing
is used on the assumption that the selection indices are always valid.)

The current HTML specification doesn't explicitly say that
selectionStart/End must remain within the length of the content, but
that does seems to be the consensus reached in a discussion of this:

https://github.com/whatwg/html/issues/2424

The test case I've added here is currently undefined in the spec which
is why I've added it in tests/wpt/mozilla.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20051)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-02-22 11:47:40 -05:00 committed by GitHub
commit f6463c89d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 255 additions and 198 deletions

View file

@ -42,7 +42,7 @@ fn test_textinput_when_inserting_multiple_lines_over_a_selection_respects_max_le
SelectionDirection::None,
);
textinput.edit_point = TextPoint { line: 0, index: 1 };
textinput.adjust_horizontal(1, Selection::NotSelected);
textinput.adjust_horizontal(3, Selection::Selected);
textinput.adjust_vertical(1, Selection::Selected);
@ -67,8 +67,7 @@ fn test_textinput_when_inserting_multiple_lines_still_respects_max_length() {
SelectionDirection::None
);
textinput.edit_point = TextPoint { line: 1, index: 0 };
textinput.adjust_vertical(1, Selection::NotSelected);
textinput.insert_string("cruel\nterrible".to_string());
assert_eq!(textinput.get_content(), "hello\ncruel\nworld");
@ -117,7 +116,7 @@ fn test_single_line_textinput_with_max_length_doesnt_allow_appending_characters_
SelectionDirection::None,
);
textinput.edit_point = TextPoint { line: 0, index: 1 };
textinput.adjust_horizontal(1, Selection::NotSelected);
textinput.adjust_horizontal(3, Selection::Selected);
// Selection is now "abcde"
@ -220,9 +219,7 @@ fn test_textinput_delete_char() {
assert_eq!(textinput.get_content(), "ab");
let mut textinput = text_input(Lines::Single, "abcdefg");
textinput.adjust_horizontal(2, Selection::NotSelected);
// Set an empty selection range.
textinput.selection_origin = Some(textinput.edit_point);
textinput.set_selection_range(2, 2, SelectionDirection::None);
textinput.delete_char(Direction::Backward);
assert_eq!(textinput.get_content(), "acdefg");
}
@ -300,16 +297,16 @@ fn test_textinput_adjust_vertical() {
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
textinput.adjust_horizontal(3, Selection::NotSelected);
textinput.adjust_vertical(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 2);
textinput.adjust_vertical(-1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 2);
textinput.adjust_vertical(2, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 2);
assert_eq!(textinput.edit_point.index, 1);
assert_eq!(textinput.edit_point().line, 2);
assert_eq!(textinput.edit_point().index, 1);
}
#[test]
@ -317,32 +314,32 @@ fn test_textinput_adjust_vertical_multibyte() {
let mut textinput = text_input(Lines::Multiple, "áé\nae");
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 2);
textinput.adjust_vertical(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 1);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 1);
}
#[test]
fn test_textinput_adjust_horizontal() {
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
textinput.adjust_horizontal(4, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 0);
textinput.adjust_horizontal(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 1);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 1);
textinput.adjust_horizontal(2, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 2);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().line, 2);
assert_eq!(textinput.edit_point().index, 0);
textinput.adjust_horizontal(-1, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 2);
}
#[test]
@ -351,45 +348,45 @@ fn test_textinput_adjust_horizontal_by_word() {
let mut textinput = text_input(Lines::Single, "abc def");
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 7);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 7);
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 4);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 4);
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 0);
// Test new line case of movement word by word based on UAX#29 rules
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 1);
assert_eq!(textinput_2.edit_point.index, 3);
assert_eq!(textinput_2.edit_point().line, 1);
assert_eq!(textinput_2.edit_point().index, 3);
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 1);
assert_eq!(textinput_2.edit_point.index, 0);
assert_eq!(textinput_2.edit_point().line, 1);
assert_eq!(textinput_2.edit_point().index, 0);
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 0);
assert_eq!(textinput_2.edit_point.index, 0);
assert_eq!(textinput_2.edit_point().line, 0);
assert_eq!(textinput_2.edit_point().index, 0);
// Test non-standard sized characters case of movement word by word based on UAX#29 rules
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 5);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 5);
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 7);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 7);
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 13);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 13);
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 11);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 11);
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 6);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 6);
}
#[test]
@ -397,29 +394,29 @@ fn test_textinput_adjust_horizontal_to_line_end() {
// Test standard case of movement to end based on UAX#29 rules
let mut textinput = text_input(Lines::Single, "abc def");
textinput.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 7);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 7);
// Test new line case of movement to end based on UAX#29 rules
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 0);
assert_eq!(textinput_2.edit_point.index, 3);
assert_eq!(textinput_2.edit_point().line, 0);
assert_eq!(textinput_2.edit_point().index, 3);
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 0);
assert_eq!(textinput_2.edit_point.index, 3);
assert_eq!(textinput_2.edit_point().line, 0);
assert_eq!(textinput_2.edit_point().index, 3);
textinput_2.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_2.edit_point.line, 0);
assert_eq!(textinput_2.edit_point.index, 0);
assert_eq!(textinput_2.edit_point().line, 0);
assert_eq!(textinput_2.edit_point().index, 0);
// Test non-standard sized characters case of movement to end based on UAX#29 rules
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
textinput_3.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 13);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 13);
textinput_3.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput_3.edit_point.line, 0);
assert_eq!(textinput_3.edit_point.index, 0);
assert_eq!(textinput_3.edit_point().line, 0);
assert_eq!(textinput_3.edit_point().index, 0);
}
#[test]
@ -429,29 +426,29 @@ fn test_navigation_keyboard_shortcuts() {
// Test that CMD + Right moves to the end of the current line.
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::SUPER);
assert_eq!(textinput.edit_point.index, 11);
assert_eq!(textinput.edit_point().index, 11);
// Test that CMD + Right moves to the beginning of the current line.
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::SUPER);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
// Test that CTRL + ALT + E moves to the end of the current line also.
textinput.handle_keydown_aux(None, Key::E, KeyModifiers::CONTROL | KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 11);
assert_eq!(textinput.edit_point().index, 11);
// Test that CTRL + ALT + A moves to the beginning of the current line also.
textinput.handle_keydown_aux(None, Key::A, KeyModifiers::CONTROL | KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
// Test that ALT + Right moves to the end of the word.
textinput.handle_keydown_aux(None, Key::Right, KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 5);
assert_eq!(textinput.edit_point().index, 5);
// Test that CTRL + ALT + F moves to the end of the word also.
textinput.handle_keydown_aux(None, Key::F, KeyModifiers::CONTROL | KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 11);
assert_eq!(textinput.edit_point().index, 11);
// Test that ALT + Left moves to the end of the word.
textinput.handle_keydown_aux(None, Key::Left, KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 6);
assert_eq!(textinput.edit_point().index, 6);
// Test that CTRL + ALT + B moves to the end of the word also.
textinput.handle_keydown_aux(None, Key::B, KeyModifiers::CONTROL | KeyModifiers::ALT);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
}
#[test]
@ -470,12 +467,12 @@ fn test_textinput_handle_return() {
#[test]
fn test_textinput_select_all() {
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 0);
textinput.select_all();
assert_eq!(textinput.edit_point.line, 2);
assert_eq!(textinput.edit_point.index, 1);
assert_eq!(textinput.edit_point().line, 2);
assert_eq!(textinput.edit_point().index, 1);
}
#[test]
@ -495,15 +492,15 @@ fn test_textinput_set_content() {
textinput.set_content(DOMString::from("abc\nf"), true);
assert_eq!(textinput.get_content(), "abc\nf");
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 0);
textinput.adjust_horizontal(3, Selection::Selected);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 3);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 3);
textinput.set_content(DOMString::from("de"), true);
assert_eq!(textinput.get_content(), "de");
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 2);
}
#[test]
@ -520,7 +517,7 @@ fn test_clipboard_paste() {
None,
SelectionDirection::None);
assert_eq!(textinput.get_content(), "defg");
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
textinput.handle_keydown_aux(Some('v'), Key::V, MODIFIERS);
assert_eq!(textinput.get_content(), "abcdefg");
}
@ -532,23 +529,23 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
// Single line - Forward
textinput.adjust_horizontal(3, Selection::Selected);
textinput.adjust_horizontal(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 3);
assert_eq!(textinput.edit_point().index, 3);
textinput.adjust_horizontal(-3, Selection::NotSelected);
textinput.adjust_horizontal(3, Selection::Selected);
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 3);
assert_eq!(textinput.edit_point().index, 3);
// Single line - Backward
textinput.adjust_horizontal(-3, Selection::NotSelected);
textinput.adjust_horizontal(3, Selection::Selected);
textinput.adjust_horizontal(-1, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
textinput.adjust_horizontal(-3, Selection::NotSelected);
textinput.adjust_horizontal(3, Selection::Selected);
textinput.adjust_horizontal_by_one(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
let mut textinput = text_input(Lines::Multiple, "abc\nde\nf");
@ -556,27 +553,27 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
// Multiline - Forward
textinput.adjust_horizontal(4, Selection::Selected);
textinput.adjust_horizontal(1, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.edit_point().line, 1);
textinput.adjust_horizontal(-4, Selection::NotSelected);
textinput.adjust_horizontal(4, Selection::Selected);
textinput.adjust_horizontal_by_one(Direction::Forward, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.edit_point().line, 1);
// Multiline - Backward
textinput.adjust_horizontal(-4, Selection::NotSelected);
textinput.adjust_horizontal(4, Selection::Selected);
textinput.adjust_horizontal(-1, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.edit_point().line, 0);
textinput.adjust_horizontal(-4, Selection::NotSelected);
textinput.adjust_horizontal(4, Selection::Selected);
textinput.adjust_horizontal_by_one(Direction::Backward, Selection::NotSelected);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.edit_point().line, 0);
}
@ -584,53 +581,53 @@ fn test_textinput_cursor_position_correct_after_clearing_selection() {
fn test_textinput_set_selection_with_direction() {
let mut textinput = text_input(Lines::Single, "abcdef");
textinput.set_selection_range(2, 6, SelectionDirection::Forward);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 6);
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 6);
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
assert!(textinput.selection_origin.is_some());
assert_eq!(textinput.selection_origin.unwrap().line, 0);
assert_eq!(textinput.selection_origin.unwrap().index, 2);
assert!(textinput.selection_origin().is_some());
assert_eq!(textinput.selection_origin().unwrap().line, 0);
assert_eq!(textinput.selection_origin().unwrap().index, 2);
textinput.set_selection_range(2, 6, SelectionDirection::Backward);
assert_eq!(textinput.edit_point.line, 0);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.selection_direction, SelectionDirection::Backward);
assert_eq!(textinput.edit_point().line, 0);
assert_eq!(textinput.edit_point().index, 2);
assert_eq!(textinput.selection_direction(), SelectionDirection::Backward);
assert!(textinput.selection_origin.is_some());
assert_eq!(textinput.selection_origin.unwrap().line, 0);
assert_eq!(textinput.selection_origin.unwrap().index, 6);
assert!(textinput.selection_origin().is_some());
assert_eq!(textinput.selection_origin().unwrap().line, 0);
assert_eq!(textinput.selection_origin().unwrap().index, 6);
textinput = text_input(Lines::Multiple, "\n\n");
textinput.set_selection_range(0, 1, SelectionDirection::Forward);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
assert!(textinput.selection_origin.is_some());
assert_eq!(textinput.selection_origin.unwrap().line, 0);
assert_eq!(textinput.selection_origin.unwrap().index, 0);
assert!(textinput.selection_origin().is_some());
assert_eq!(textinput.selection_origin().unwrap().line, 0);
assert_eq!(textinput.selection_origin().unwrap().index, 0);
textinput = text_input(Lines::Multiple, "\n");
textinput.set_selection_range(0, 1, SelectionDirection::Forward);
assert_eq!(textinput.edit_point.line, 1);
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.selection_direction, SelectionDirection::Forward);
assert_eq!(textinput.edit_point().line, 1);
assert_eq!(textinput.edit_point().index, 0);
assert_eq!(textinput.selection_direction(), SelectionDirection::Forward);
assert!(textinput.selection_origin.is_some());
assert_eq!(textinput.selection_origin.unwrap().line, 0);
assert_eq!(textinput.selection_origin.unwrap().index, 0);
assert!(textinput.selection_origin().is_some());
assert_eq!(textinput.selection_origin().unwrap().line, 0);
assert_eq!(textinput.selection_origin().unwrap().index, 0);
}
#[test]
fn test_textinput_unicode_handling() {
let mut textinput = text_input(Lines::Single, "éèùµ$£");
assert_eq!(textinput.edit_point.index, 0);
assert_eq!(textinput.edit_point().index, 0);
textinput.set_edit_point_index(1);
assert_eq!(textinput.edit_point.index, 2);
assert_eq!(textinput.edit_point().index, 2);
textinput.set_edit_point_index(4);
assert_eq!(textinput.edit_point.index, 8);
assert_eq!(textinput.edit_point().index, 8);
}
#[test]

View file

@ -39133,6 +39133,12 @@
{}
]
],
"mozilla/textcontrol-selection-cannot-exceed-content.html": [
[
"/_mozilla/mozilla/textcontrol-selection-cannot-exceed-content.html",
{}
]
],
"mozilla/timeout-in-discarded-document.html": [
[
"/_mozilla/mozilla/timeout-in-discarded-document.html",
@ -70782,6 +70788,10 @@
"094fbd794b78520d6c2d8aae549557bed3529a7a",
"testharness"
],
"mozilla/textcontrol-selection-cannot-exceed-content.html": [
"f8b982ba0abb23f8e53ef28413e8da2f8dd7ca17",
"testharness"
],
"mozilla/timeout-in-discarded-document.html": [
"7ff88491f20ee72ed40aa5ce4e84840b98d5eef5",
"testharness"

View file

@ -0,0 +1,25 @@
<!doctype html>
<meta charset="utf-8">
<title>The selection bounds of a text control should never exceed the content</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<input type="text" value="lorem ">
<script>
test(() => {
const el = document.querySelector("input");
el.setSelectionRange("lorem".length + 1, "lorem".length + 2);
assert_equals(el.selectionStart, "lorem".length + 1);
assert_equals(el.selectionEnd, "lorem".length + 2);
// This will invoke the value sanitization algorithm for a url field, which strips trailing
// whitespace from the raw value.
el.type = "url";
assert_equals(el.selectionStart, "lorem".length);
assert_equals(el.selectionEnd, "lorem".length);
});
</script>