blob: 54fb543530808b046e79942eabe5214ffae363b2 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "public/web/WebSurroundingText.h"
#include <memory>
#include "core/dom/Document.h"
#include "core/dom/Range.h"
#include "core/dom/Text.h"
#include "core/editing/EphemeralRange.h"
#include "core/editing/Position.h"
#include "core/editing/SelectionTemplate.h"
#include "core/html/HTMLElement.h"
#include "core/html/forms/TextControlElement.h"
#include "core/testing/DummyPageHolder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
class WebSurroundingTextTest : public ::testing::Test {
protected:
Document& GetDocument() const { return dummy_page_holder_->GetDocument(); }
void SetHTML(const String&);
EphemeralRange Select(int offset) { return Select(offset, offset); }
EphemeralRange Select(int start, int end);
private:
void SetUp() override;
std::unique_ptr<DummyPageHolder> dummy_page_holder_;
};
void WebSurroundingTextTest::SetUp() {
dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
}
void WebSurroundingTextTest::SetHTML(const String& content) {
GetDocument().body()->SetInnerHTMLFromString(content);
GetDocument().UpdateStyleAndLayout();
}
EphemeralRange WebSurroundingTextTest::Select(int start, int end) {
Element* element = GetDocument().getElementById("selection");
return EphemeralRange(Position(element->firstChild(), start),
Position(element->firstChild(), end));
}
TEST_F(WebSurroundingTextTest, BasicCaretSelection) {
SetHTML(String("<p id='selection'>foo bar</p>"));
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 1);
EXPECT_EQ("f", surrounding_text.TextContent());
EXPECT_EQ(0u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(0u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 5);
// maxlength/2 is used on the left and right.
EXPECT_EQ("foo",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 42);
EXPECT_EQ("foo bar",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(7);
WebSurroundingText surrounding_text(selection, 42);
EXPECT_EQ("foo bar",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(8u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(8u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6);
WebSurroundingText surrounding_text(selection, 2);
EXPECT_EQ("ar", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6);
WebSurroundingText surrounding_text(selection, 42);
EXPECT_EQ("foo bar",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(7u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(7u, surrounding_text.EndOffsetInTextContent());
}
}
TEST_F(WebSurroundingTextTest, BasicRangeSelection) {
SetHTML(String("<p id='selection'>Lorem ipsum dolor sit amet</p>"));
{
EphemeralRange selection = Select(0, 5);
WebSurroundingText surrounding_text(selection, 1);
EXPECT_EQ("Lorem ", surrounding_text.TextContent());
EXPECT_EQ(0u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(5u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0, 5);
WebSurroundingText surrounding_text(selection, 5);
EXPECT_EQ("Lorem ip",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0, 5);
WebSurroundingText surrounding_text(selection, 42);
EXPECT_EQ("Lorem ipsum dolor sit amet",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6, 11);
WebSurroundingText surrounding_text(selection, 2);
EXPECT_EQ(" ipsum ", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6, 11);
WebSurroundingText surrounding_text(selection, 42);
EXPECT_EQ("Lorem ipsum dolor sit amet",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(7u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(12u, surrounding_text.EndOffsetInTextContent());
}
{
// Last word.
EphemeralRange selection = Select(22, 26);
WebSurroundingText surrounding_text(selection, 8);
EXPECT_EQ("sit amet", surrounding_text.TextContent());
EXPECT_EQ(4u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(8u, surrounding_text.EndOffsetInTextContent());
}
}
TEST_F(WebSurroundingTextTest, TreeCaretSelection) {
SetHTML(
String("<div>This is outside of <p id='selection'>foo bar</p> the "
"selected node</div>"));
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 1);
EXPECT_EQ("f", surrounding_text.TextContent());
EXPECT_EQ(0u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(0u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 5);
EXPECT_EQ("foo",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 1337);
EXPECT_EQ("This is outside of foo bar the selected node",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(20u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(20u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6);
WebSurroundingText surrounding_text(selection, 2);
EXPECT_EQ("ar", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6);
WebSurroundingText surrounding_text(selection, 1337);
EXPECT_EQ("This is outside of foo bar the selected node",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(26u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(26u, surrounding_text.EndOffsetInTextContent());
}
}
TEST_F(WebSurroundingTextTest, TreeRangeSelection) {
SetHTML(
String("<div>This is outside of <p id='selection'>foo bar</p> the "
"selected node</div>"));
{
EphemeralRange selection = Select(0, 1);
WebSurroundingText surrounding_text(selection, 1);
EXPECT_EQ("fo",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(0u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0, 3);
WebSurroundingText surrounding_text(selection, 12);
EXPECT_EQ("e of foo bar",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(5u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(8u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0, 3);
WebSurroundingText surrounding_text(selection, 1337);
EXPECT_EQ("This is outside of foo bar the selected node",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(20u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(23u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(4, 7);
WebSurroundingText surrounding_text(selection, 12);
EXPECT_EQ("foo bar the se",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(5u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(8u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0, 7);
WebSurroundingText surrounding_text(selection, 1337);
EXPECT_EQ("This is outside of foo bar the selected node",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(20u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(27u, surrounding_text.EndOffsetInTextContent());
}
}
TEST_F(WebSurroundingTextTest, TextAreaSelection) {
SetHTML(
String("<p>First paragraph</p>"
"<textarea id='selection'>abc def ghi</textarea>"
"<p>Second paragraph</p>"));
TextControlElement* text_ctrl =
(TextControlElement*)GetDocument().getElementById("selection");
text_ctrl->SetSelectionRange(4, 7);
EphemeralRange selection = text_ctrl->Selection().ComputeRange();
WebSurroundingText surrounding_text(selection, 20);
EXPECT_EQ("abc def ghi",
String(surrounding_text.TextContent()).SimplifyWhiteSpace());
EXPECT_EQ(4u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(7u, surrounding_text.EndOffsetInTextContent());
}
TEST_F(WebSurroundingTextTest, EmptyInputElementWithChild) {
SetHTML(String("<input type=\"text\" id=\"input_name\"/>"));
TextControlElement* input_element =
(TextControlElement*)GetDocument().getElementById("input_name");
input_element->SetInnerEditorValue("John Smith");
GetDocument().UpdateStyleAndLayout();
// BODY
// INPUT
// #shadow-root
// * DIV id="inner-editor" (editable)
// #text "John Smith"
const Element* inner_editor = input_element->InnerEditorElement();
const Position start = Position(inner_editor, 0);
const Position end = Position(inner_editor, 0);
// Surrounding text should not crash. See http://crbug.com/758438.
WebSurroundingText surrounding_text(EphemeralRange(start, end), 8);
EXPECT_TRUE(surrounding_text.TextContent().IsEmpty());
}
TEST_F(WebSurroundingTextTest, ButtonsAndParagraph) {
SetHTML(
String("<button>.</button>12345"
"<p id='selection'>6789 12345</p>"
"6789<button>.</button>"));
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_EQ("12345\n6789 12345\n\n6789", surrounding_text.TextContent());
EXPECT_EQ(6u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(5);
WebSurroundingText surrounding_text(selection, 6);
EXPECT_EQ("89 123", surrounding_text.TextContent());
EXPECT_EQ(3u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(3u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 0);
EXPECT_TRUE(surrounding_text.TextContent().IsEmpty());
}
{
EphemeralRange selection = Select(5);
WebSurroundingText surrounding_text(selection, 1);
EXPECT_EQ("1", surrounding_text.TextContent());
EXPECT_EQ(0u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(0u, surrounding_text.EndOffsetInTextContent());
}
{
EphemeralRange selection = Select(6);
WebSurroundingText surrounding_text(selection, 2);
EXPECT_EQ("12", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
}
TEST_F(WebSurroundingTextTest, SelectElementAndText) {
SetHTML(String(
"<select>.</select>"
"<div>57th Street and Lake Shore Drive</div>"
" <span>Chicago</span> <span id='selection'>IL</span> <span>60637</span>"
"<select>.</select>"));
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_STREQ(
"\xEF\xBF\xBC\n57th Street and Lake Shore Drive\nChicago IL 60637",
surrounding_text.TextContent().Utf8().data());
EXPECT_EQ(43u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(43u, surrounding_text.EndOffsetInTextContent());
}
TEST_F(WebSurroundingTextTest, FieldsetElementAndText) {
SetHTML(
String("<fieldset>.</fieldset>12345<button>abc</button>"
"<p>6789<br><span id='selection'>12345</span></p>"
"6789<textarea>abc</textarea>0123<fieldset>.</fieldset>"));
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_EQ("\n6789\n12345\n\n6789", surrounding_text.TextContent());
EXPECT_EQ(6u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
TEST_F(WebSurroundingTextTest, ButtonScriptAndComment) {
SetHTML(
String("<button>.</button>"
"<div id='selection'>This is <!-- comment --!>a test "
"<script language='javascript'></script>"
"example<button>.</button>"));
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_EQ("\nThis is a test example", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
TEST_F(WebSurroundingTextTest, ButtonAndLongDiv) {
SetHTML(
String("<button>.</button>"
"<div id='selection'>012345678901234567890123456789</div>"
"<button>.</button>"));
EphemeralRange selection = Select(15);
WebSurroundingText surrounding_text(selection, 12);
EXPECT_EQ("901234567890", surrounding_text.TextContent());
EXPECT_EQ(6u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(6u, surrounding_text.EndOffsetInTextContent());
}
TEST_F(WebSurroundingTextTest, EmptyWebSurroundingTextInOptionsAndButton) {
SetHTML(
String("<option>.</option>12345"
"<button id='selection'>test</button>"
"<option>.</option>"));
{
EphemeralRange selection = Select(1);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_TRUE(surrounding_text.TextContent().IsEmpty());
}
{
EphemeralRange selection = Select(3);
WebSurroundingText surrounding_text(selection, 100);
EXPECT_TRUE(surrounding_text.TextContent().IsEmpty());
}
}
TEST_F(WebSurroundingTextTest, SingleDotParagraph) {
SetHTML(String("<p id='selection'>.</p>"));
EphemeralRange selection = Select(0);
WebSurroundingText surrounding_text(selection, 2);
EXPECT_EQ("\n.", surrounding_text.TextContent());
EXPECT_EQ(1u, surrounding_text.StartOffsetInTextContent());
EXPECT_EQ(1u, surrounding_text.EndOffsetInTextContent());
}
} // namespace blink