Home | History | Annotate | Download | only in editing
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "config.h"
      6 #include "core/editing/InputMethodController.h"
      7 
      8 #include "core/dom/Element.h"
      9 #include "core/dom/Range.h"
     10 #include "core/frame/LocalFrame.h"
     11 #include "core/html/HTMLDocument.h"
     12 #include "core/html/HTMLInputElement.h"
     13 #include "core/testing/DummyPageHolder.h"
     14 #include <gtest/gtest.h>
     15 
     16 using namespace blink;
     17 
     18 namespace {
     19 
     20 class InputMethodControllerTest : public ::testing::Test {
     21 protected:
     22     InputMethodController& controller() { return frame().inputMethodController(); }
     23     HTMLDocument& document() const { return *m_document; }
     24     LocalFrame& frame() const { return m_dummyPageHolder->frame(); }
     25     Element* insertHTMLElement(const char* elementCode, const char* elementId);
     26 
     27 private:
     28     virtual void SetUp() OVERRIDE;
     29 
     30     OwnPtr<DummyPageHolder> m_dummyPageHolder;
     31     HTMLDocument* m_document;
     32 };
     33 
     34 void InputMethodControllerTest::SetUp()
     35 {
     36     m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
     37     m_document = toHTMLDocument(&m_dummyPageHolder->document());
     38     ASSERT(m_document);
     39 }
     40 
     41 Element* InputMethodControllerTest::insertHTMLElement(
     42     const char* elementCode, const char* elementId)
     43 {
     44     document().write(elementCode);
     45     document().updateLayout();
     46     Element* element = document().getElementById(elementId);
     47     element->focus();
     48     return element;
     49 }
     50 
     51 TEST_F(InputMethodControllerTest, BackspaceFromEndOfInput)
     52 {
     53     HTMLInputElement* input = toHTMLInputElement(
     54         insertHTMLElement("<input id='sample'>", "sample"));
     55 
     56     input->setValue("fooX");
     57     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     58     EXPECT_STREQ("fooX", input->value().utf8().data());
     59     controller().extendSelectionAndDelete(0, 0);
     60     EXPECT_STREQ("fooX", input->value().utf8().data());
     61 
     62     input->setValue("fooX");
     63     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     64     EXPECT_STREQ("fooX", input->value().utf8().data());
     65     controller().extendSelectionAndDelete(1, 0);
     66     EXPECT_STREQ("foo", input->value().utf8().data());
     67 
     68     input->setValue(String::fromUTF8("foo\xE2\x98\x85")); // U+2605 == "black star"
     69     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     70     EXPECT_STREQ("foo\xE2\x98\x85", input->value().utf8().data());
     71     controller().extendSelectionAndDelete(1, 0);
     72     EXPECT_STREQ("foo", input->value().utf8().data());
     73 
     74     input->setValue(String::fromUTF8("foo\xF0\x9F\x8F\x86")); // U+1F3C6 == "trophy"
     75     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     76     EXPECT_STREQ("foo\xF0\x9F\x8F\x86", input->value().utf8().data());
     77     controller().extendSelectionAndDelete(1, 0);
     78     EXPECT_STREQ("foo", input->value().utf8().data());
     79 
     80     input->setValue(String::fromUTF8("foo\xE0\xB8\x81\xE0\xB9\x89")); // composed U+0E01 "ka kai" + U+0E49 "mai tho"
     81     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     82     EXPECT_STREQ("foo\xE0\xB8\x81\xE0\xB9\x89", input->value().utf8().data());
     83     controller().extendSelectionAndDelete(1, 0);
     84     EXPECT_STREQ("foo", input->value().utf8().data());
     85 
     86     input->setValue("fooX");
     87     controller().setEditableSelectionOffsets(PlainTextRange(4, 4));
     88     EXPECT_STREQ("fooX", input->value().utf8().data());
     89     controller().extendSelectionAndDelete(0, 1);
     90     EXPECT_STREQ("fooX", input->value().utf8().data());
     91 }
     92 
     93 TEST_F(InputMethodControllerTest, SetCompositionFromExistingText)
     94 {
     95     Element* div = insertHTMLElement(
     96         "<div id='sample' contenteditable='true'>hello world</div>", "sample");
     97 
     98     Vector<CompositionUnderline> underlines;
     99     underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    100     controller().setCompositionFromExistingText(underlines, 0, 5);
    101 
    102     RefPtrWillBeRawPtr<Range> range = controller().compositionRange();
    103     EXPECT_EQ(0, range->startOffset());
    104     EXPECT_EQ(5, range->endOffset());
    105 
    106     PlainTextRange plainTextRange(PlainTextRange::create(*div, *range.get()));
    107     EXPECT_EQ(0u, plainTextRange.start());
    108     EXPECT_EQ(5u, plainTextRange.end());
    109 }
    110 
    111 TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithCollapsedWhiteSpace)
    112 {
    113     // Creates a div with one leading new line char. The new line char is hidden
    114     // from the user and IME, but is visible to InputMethodController.
    115     Element* div = insertHTMLElement(
    116         "<div id='sample' contenteditable='true'>\nhello world</div>", "sample");
    117 
    118     Vector<CompositionUnderline> underlines;
    119     underlines.append(CompositionUnderline(0, 5, Color(255, 0, 0), false, 0));
    120     controller().setCompositionFromExistingText(underlines, 0, 5);
    121 
    122     RefPtrWillBeRawPtr<Range> range = controller().compositionRange();
    123     EXPECT_EQ(1, range->startOffset());
    124     EXPECT_EQ(6, range->endOffset());
    125 
    126     PlainTextRange plainTextRange(PlainTextRange::create(*div, *range.get()));
    127     EXPECT_EQ(0u, plainTextRange.start());
    128     EXPECT_EQ(5u, plainTextRange.end());
    129 }
    130 
    131 TEST_F(InputMethodControllerTest, SetCompositionFromExistingTextWithInvalidOffsets)
    132 {
    133     insertHTMLElement("<div id='sample' contenteditable='true'>test</div>", "sample");
    134 
    135     Vector<CompositionUnderline> underlines;
    136     underlines.append(CompositionUnderline(7, 8, Color(255, 0, 0), false, 0));
    137     controller().setCompositionFromExistingText(underlines, 7, 8);
    138 
    139     EXPECT_FALSE(controller().compositionRange());
    140 }
    141 
    142 } // namespace
    143