Home | History | Annotate | Download | only in tests
      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 
      7 #include "web/TextFinder.h"
      8 
      9 #include "bindings/v8/ExceptionStatePlaceholder.h"
     10 #include "core/dom/Document.h"
     11 #include "core/dom/NodeList.h"
     12 #include "core/dom/Range.h"
     13 #include "core/dom/shadow/ShadowRoot.h"
     14 #include "core/html/HTMLElement.h"
     15 #include "public/web/WebDocument.h"
     16 #include "web/FindInPageCoordinates.h"
     17 #include "web/WebLocalFrameImpl.h"
     18 #include "web/tests/FrameTestHelpers.h"
     19 #include "wtf/OwnPtr.h"
     20 #include <gtest/gtest.h>
     21 
     22 using namespace blink;
     23 using namespace WebCore;
     24 
     25 namespace {
     26 
     27 class TextFinderTest : public ::testing::Test {
     28 protected:
     29     virtual void SetUp() OVERRIDE;
     30 
     31     Document& document() const;
     32     TextFinder& textFinder() const;
     33 
     34     static WebFloatRect findInPageRect(Node* startContainer, int startOffset, Node* endContainer, int endOffset);
     35 
     36 private:
     37     FrameTestHelpers::WebViewHelper m_webViewHelper;
     38     RefPtrWillBePersistent<Document> m_document;
     39     TextFinder* m_textFinder;
     40 };
     41 
     42 void TextFinderTest::SetUp()
     43 {
     44     m_webViewHelper.initialize();
     45     WebLocalFrameImpl& frameImpl = *m_webViewHelper.webViewImpl()->mainFrameImpl();
     46     frameImpl.viewImpl()->resize(WebSize(640, 480));
     47     m_document = PassRefPtrWillBeRawPtr<Document>(frameImpl.document());
     48     m_textFinder = &frameImpl.ensureTextFinder();
     49 }
     50 
     51 Document& TextFinderTest::document() const
     52 {
     53     return *m_document;
     54 }
     55 
     56 TextFinder& TextFinderTest::textFinder() const
     57 {
     58     return *m_textFinder;
     59 }
     60 
     61 WebFloatRect TextFinderTest::findInPageRect(Node* startContainer, int startOffset, Node* endContainer, int endOffset)
     62 {
     63     RefPtrWillBeRawPtr<Range> range = Range::create(startContainer->document(), startContainer, startOffset, endContainer, endOffset);
     64     return WebFloatRect(findInPageRectFromRange(range.get()));
     65 }
     66 
     67 TEST_F(TextFinderTest, FindTextSimple)
     68 {
     69     document().body()->setInnerHTML("XXXXFindMeYYYYfindmeZZZZ", ASSERT_NO_EXCEPTION);
     70     Node* textNode = document().body()->firstChild();
     71 
     72     int identifier = 0;
     73     WebString searchText(String("FindMe"));
     74     WebFindOptions findOptions; // Default.
     75     bool wrapWithinFrame = true;
     76     WebRect* selectionRect = 0;
     77 
     78     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
     79     Range* activeMatch = textFinder().activeMatch();
     80     ASSERT_TRUE(activeMatch);
     81     EXPECT_EQ(textNode, activeMatch->startContainer());
     82     EXPECT_EQ(4, activeMatch->startOffset());
     83     EXPECT_EQ(textNode, activeMatch->endContainer());
     84     EXPECT_EQ(10, activeMatch->endOffset());
     85 
     86     findOptions.findNext = true;
     87     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
     88     activeMatch = textFinder().activeMatch();
     89     ASSERT_TRUE(activeMatch);
     90     EXPECT_EQ(textNode, activeMatch->startContainer());
     91     EXPECT_EQ(14, activeMatch->startOffset());
     92     EXPECT_EQ(textNode, activeMatch->endContainer());
     93     EXPECT_EQ(20, activeMatch->endOffset());
     94 
     95     // Should wrap to the first match.
     96     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
     97     activeMatch = textFinder().activeMatch();
     98     ASSERT_TRUE(activeMatch);
     99     EXPECT_EQ(textNode, activeMatch->startContainer());
    100     EXPECT_EQ(4, activeMatch->startOffset());
    101     EXPECT_EQ(textNode, activeMatch->endContainer());
    102     EXPECT_EQ(10, activeMatch->endOffset());
    103 
    104     // Search in the reverse order.
    105     identifier = 1;
    106     findOptions = WebFindOptions();
    107     findOptions.forward = false;
    108 
    109     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    110     activeMatch = textFinder().activeMatch();
    111     ASSERT_TRUE(activeMatch);
    112     EXPECT_EQ(textNode, activeMatch->startContainer());
    113     EXPECT_EQ(14, activeMatch->startOffset());
    114     EXPECT_EQ(textNode, activeMatch->endContainer());
    115     EXPECT_EQ(20, activeMatch->endOffset());
    116 
    117     findOptions.findNext = true;
    118     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    119     activeMatch = textFinder().activeMatch();
    120     ASSERT_TRUE(activeMatch);
    121     EXPECT_EQ(textNode, activeMatch->startContainer());
    122     EXPECT_EQ(4, activeMatch->startOffset());
    123     EXPECT_EQ(textNode, activeMatch->endContainer());
    124     EXPECT_EQ(10, activeMatch->endOffset());
    125 
    126     // Wrap to the first match (last occurence in the document).
    127     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    128     activeMatch = textFinder().activeMatch();
    129     ASSERT_TRUE(activeMatch);
    130     EXPECT_EQ(textNode, activeMatch->startContainer());
    131     EXPECT_EQ(14, activeMatch->startOffset());
    132     EXPECT_EQ(textNode, activeMatch->endContainer());
    133     EXPECT_EQ(20, activeMatch->endOffset());
    134 }
    135 
    136 TEST_F(TextFinderTest, FindTextNotFound)
    137 {
    138     document().body()->setInnerHTML("XXXXFindMeYYYYfindmeZZZZ", ASSERT_NO_EXCEPTION);
    139 
    140     int identifier = 0;
    141     WebString searchText(String("Boo"));
    142     WebFindOptions findOptions; // Default.
    143     bool wrapWithinFrame = true;
    144     WebRect* selectionRect = 0;
    145 
    146     EXPECT_FALSE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    147     EXPECT_FALSE(textFinder().activeMatch());
    148 }
    149 
    150 TEST_F(TextFinderTest, FindTextInShadowDOM)
    151 {
    152     document().body()->setInnerHTML("<b>FOO</b><i>foo</i>", ASSERT_NO_EXCEPTION);
    153     RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = document().body()->createShadowRoot(ASSERT_NO_EXCEPTION);
    154     shadowRoot->setInnerHTML("<content select=\"i\"></content><u>Foo</u><content></content>", ASSERT_NO_EXCEPTION);
    155     Node* textInBElement = document().body()->firstChild()->firstChild();
    156     Node* textInIElement = document().body()->lastChild()->firstChild();
    157     Node* textInUElement = shadowRoot->childNodes()->item(1)->firstChild();
    158 
    159     int identifier = 0;
    160     WebString searchText(String("foo"));
    161     WebFindOptions findOptions; // Default.
    162     bool wrapWithinFrame = true;
    163     WebRect* selectionRect = 0;
    164 
    165     // TextIterator currently returns the matches in the document order, instead of the visual order. It visits
    166     // the shadow roots first, so in this case the matches will be returned in the order of <u> -> <b> -> <i>.
    167     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    168     Range* activeMatch = textFinder().activeMatch();
    169     ASSERT_TRUE(activeMatch);
    170     EXPECT_EQ(textInUElement, activeMatch->startContainer());
    171     EXPECT_EQ(0, activeMatch->startOffset());
    172     EXPECT_EQ(textInUElement, activeMatch->endContainer());
    173     EXPECT_EQ(3, activeMatch->endOffset());
    174 
    175     findOptions.findNext = true;
    176     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    177     activeMatch = textFinder().activeMatch();
    178     ASSERT_TRUE(activeMatch);
    179     EXPECT_EQ(textInBElement, activeMatch->startContainer());
    180     EXPECT_EQ(0, activeMatch->startOffset());
    181     EXPECT_EQ(textInBElement, activeMatch->endContainer());
    182     EXPECT_EQ(3, activeMatch->endOffset());
    183 
    184     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    185     activeMatch = textFinder().activeMatch();
    186     ASSERT_TRUE(activeMatch);
    187     EXPECT_EQ(textInIElement, activeMatch->startContainer());
    188     EXPECT_EQ(0, activeMatch->startOffset());
    189     EXPECT_EQ(textInIElement, activeMatch->endContainer());
    190     EXPECT_EQ(3, activeMatch->endOffset());
    191 
    192     // Should wrap to the first match.
    193     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    194     activeMatch = textFinder().activeMatch();
    195     ASSERT_TRUE(activeMatch);
    196     EXPECT_EQ(textInUElement, activeMatch->startContainer());
    197     EXPECT_EQ(0, activeMatch->startOffset());
    198     EXPECT_EQ(textInUElement, activeMatch->endContainer());
    199     EXPECT_EQ(3, activeMatch->endOffset());
    200 
    201     // Fresh search in the reverse order.
    202     identifier = 1;
    203     findOptions = WebFindOptions();
    204     findOptions.forward = false;
    205 
    206     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    207     activeMatch = textFinder().activeMatch();
    208     ASSERT_TRUE(activeMatch);
    209     EXPECT_EQ(textInIElement, activeMatch->startContainer());
    210     EXPECT_EQ(0, activeMatch->startOffset());
    211     EXPECT_EQ(textInIElement, activeMatch->endContainer());
    212     EXPECT_EQ(3, activeMatch->endOffset());
    213 
    214     findOptions.findNext = true;
    215     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    216     activeMatch = textFinder().activeMatch();
    217     ASSERT_TRUE(activeMatch);
    218     EXPECT_EQ(textInBElement, activeMatch->startContainer());
    219     EXPECT_EQ(0, activeMatch->startOffset());
    220     EXPECT_EQ(textInBElement, activeMatch->endContainer());
    221     EXPECT_EQ(3, activeMatch->endOffset());
    222 
    223     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    224     activeMatch = textFinder().activeMatch();
    225     ASSERT_TRUE(activeMatch);
    226     EXPECT_EQ(textInUElement, activeMatch->startContainer());
    227     EXPECT_EQ(0, activeMatch->startOffset());
    228     EXPECT_EQ(textInUElement, activeMatch->endContainer());
    229     EXPECT_EQ(3, activeMatch->endOffset());
    230 
    231     // And wrap.
    232     ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect));
    233     activeMatch = textFinder().activeMatch();
    234     ASSERT_TRUE(activeMatch);
    235     EXPECT_EQ(textInIElement, activeMatch->startContainer());
    236     EXPECT_EQ(0, activeMatch->startOffset());
    237     EXPECT_EQ(textInIElement, activeMatch->endContainer());
    238     EXPECT_EQ(3, activeMatch->endOffset());
    239 }
    240 
    241 TEST_F(TextFinderTest, ScopeTextMatchesSimple)
    242 {
    243     document().body()->setInnerHTML("XXXXFindMeYYYYfindmeZZZZ", ASSERT_NO_EXCEPTION);
    244     Node* textNode = document().body()->firstChild();
    245 
    246     int identifier = 0;
    247     WebString searchText(String("FindMe"));
    248     WebFindOptions findOptions; // Default.
    249 
    250     textFinder().resetMatchCount();
    251     textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
    252     while (textFinder().scopingInProgress())
    253         FrameTestHelpers::runPendingTasks();
    254 
    255     EXPECT_EQ(2, textFinder().totalMatchCount());
    256     WebVector<WebFloatRect> matchRects;
    257     textFinder().findMatchRects(matchRects);
    258     ASSERT_EQ(2u, matchRects.size());
    259     EXPECT_EQ(findInPageRect(textNode, 4, textNode, 10), matchRects[0]);
    260     EXPECT_EQ(findInPageRect(textNode, 14, textNode, 20), matchRects[1]);
    261 }
    262 
    263 TEST_F(TextFinderTest, ScopeTextMatchesWithShadowDOM)
    264 {
    265     document().body()->setInnerHTML("<b>FOO</b><i>foo</i>", ASSERT_NO_EXCEPTION);
    266     RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = document().body()->createShadowRoot(ASSERT_NO_EXCEPTION);
    267     shadowRoot->setInnerHTML("<content select=\"i\"></content><u>Foo</u><content></content>", ASSERT_NO_EXCEPTION);
    268     Node* textInBElement = document().body()->firstChild()->firstChild();
    269     Node* textInIElement = document().body()->lastChild()->firstChild();
    270     Node* textInUElement = shadowRoot->childNodes()->item(1)->firstChild();
    271 
    272     int identifier = 0;
    273     WebString searchText(String("fOO"));
    274     WebFindOptions findOptions; // Default.
    275 
    276     textFinder().resetMatchCount();
    277     textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
    278     while (textFinder().scopingInProgress())
    279         FrameTestHelpers::runPendingTasks();
    280 
    281     // TextIterator currently returns the matches in the document order, instead of the visual order. It visits
    282     // the shadow roots first, so in this case the matches will be returned in the order of <u> -> <b> -> <i>.
    283     EXPECT_EQ(3, textFinder().totalMatchCount());
    284     WebVector<WebFloatRect> matchRects;
    285     textFinder().findMatchRects(matchRects);
    286     ASSERT_EQ(3u, matchRects.size());
    287     EXPECT_EQ(findInPageRect(textInUElement, 0, textInUElement, 3), matchRects[0]);
    288     EXPECT_EQ(findInPageRect(textInBElement, 0, textInBElement, 3), matchRects[1]);
    289     EXPECT_EQ(findInPageRect(textInIElement, 0, textInIElement, 3), matchRects[2]);
    290 }
    291 
    292 } // namespace
    293