// Copyright 2018 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 "third_party/blink/renderer/core/editing/finder/find_buffer.h" #include "build/build_config.h" #include "third_party/blink/renderer/core/editing/ephemeral_range.h" #include "third_party/blink/renderer/core/editing/selection_template.h" #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h" namespace blink { class FindBufferTest : public EditingTestBase { protected: PositionInFlatTree LastPositionInDocument() { return GetDocument().documentElement()->lastChild() ? PositionInFlatTree::AfterNode( *GetDocument().documentElement()->lastChild()) : PositionInFlatTree::LastPositionInNode( *GetDocument().documentElement()); } EphemeralRangeInFlatTree WholeDocumentRange() { return EphemeralRangeInFlatTree(PositionInFlatTree::FirstPositionInNode( *GetDocument().documentElement()), LastPositionInDocument()); } PositionInFlatTree PositionFromParentId(const char* id, unsigned offset) { return PositionInFlatTree(GetElementById(id)->firstChild(), offset); } std::string SerializeRange(const EphemeralRangeInFlatTree& range) { return GetSelectionTextInFlatTreeFromBody( SelectionInFlatTree::Builder().SetAsForwardSelection(range).Build()); } }; TEST_F(FindBufferTest, FindInline) { SetBodyContent( "
abc
d
e
"); FindBuffer buffer(WholeDocumentRange()); EXPECT_TRUE(buffer.PositionAfterBlock().IsNull()); std::unique_ptr results = buffer.FindMatches("abce", kCaseInsensitive); EXPECT_EQ(1u, results->CountForTesting()); FindBuffer::BufferMatchResult match = *results->begin(); EXPECT_EQ(0u, match.start); EXPECT_EQ(4u, match.length); EXPECT_EQ( EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("inline-div", 1)), buffer.RangeFromBufferIndex(match.start, match.start + match.length)); } TEST_F(FindBufferTest, RangeFromBufferIndex) { SetBodyContent( "
a bcc
d
e
"); FindBuffer buffer(WholeDocumentRange()); // Range for "a" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("container", 1)), buffer.RangeFromBufferIndex(0, 1)); EXPECT_EQ( "
^a| bcc
d
e
", SerializeRange(buffer.RangeFromBufferIndex(0, 1))); // Range for "a " EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("container", 2)), buffer.RangeFromBufferIndex(0, 2)); EXPECT_EQ( "
^a | bcc
d
e
", SerializeRange(buffer.RangeFromBufferIndex(0, 2))); // Range for "a b" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("span", 2)), buffer.RangeFromBufferIndex(0, 3)); EXPECT_EQ( "
^a b|cc
d
e
", SerializeRange(buffer.RangeFromBufferIndex(0, 3))); // Range for "a bc" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("b", 1)), buffer.RangeFromBufferIndex(0, 4)); EXPECT_EQ( "
^a bc|c
d
e
", SerializeRange(buffer.RangeFromBufferIndex(0, 4))); // Range for "a bcc" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("b", 2)), buffer.RangeFromBufferIndex(0, 5)); EXPECT_EQ( "
^a bcc|
d
e
", SerializeRange(buffer.RangeFromBufferIndex(0, 5))); // Range for "a bcce" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 0), PositionFromParentId("inline-div", 1)), buffer.RangeFromBufferIndex(0, 6)); EXPECT_EQ( "
^a bcc
d
e|
", SerializeRange(buffer.RangeFromBufferIndex(0, 6))); // Range for " b" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 1), PositionFromParentId("span", 2)), buffer.RangeFromBufferIndex(1, 3)); EXPECT_EQ( "
a^ b|cc
d
e
", SerializeRange(buffer.RangeFromBufferIndex(1, 3))); // Range for " bc" EXPECT_EQ(EphemeralRangeInFlatTree(PositionFromParentId("container", 1), PositionFromParentId("b", 1)), buffer.RangeFromBufferIndex(1, 4)); EXPECT_EQ( "
a^ bc|c
d
e
", SerializeRange(buffer.RangeFromBufferIndex(1, 4))); } TEST_F(FindBufferTest, FindBetweenPositionsSameNode) { PositionInFlatTree start_position = ToPositionInFlatTree(SetCaretTextToBody("f|oofoo")); Node* node = start_position.ComputeContainerNode(); // |end_position| = foofoo| (end of text). PositionInFlatTree end_position = PositionInFlatTree::LastPositionInNode(*node); FindBuffer buffer(EphemeralRangeInFlatTree(start_position, end_position)); EXPECT_EQ(1u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(4u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); // |start_position| = fo|ofoo // |end_position| = foof|oo start_position = PositionInFlatTree(*node, 2u); end_position = PositionInFlatTree(*node, 4u); buffer = FindBuffer(EphemeralRangeInFlatTree(start_position, end_position)); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, FindBetweenPositionsDifferentNodes) { SetBodyContent( "
foofoofoo
"); Element* div = GetElementById("div"); Element* span = GetElementById("span"); Element* b = GetElementById("b"); //
^foofoof|oo
// So buffer = "foofoof" FindBuffer buffer(EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*div->firstChild()), PositionInFlatTree::LastPositionInNode(*span->firstChild()))); EXPECT_EQ(2u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("fo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("oof", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(4u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(3u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
f^oofoofo|o
// So buffer = "oofoofo" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*div->firstChild(), 1), PositionInFlatTree(*b->firstChild(), 1))); EXPECT_EQ(1u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("oof", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("fo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(5u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
foof^oof|oo
// So buffer = "oof" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*span->firstChild(), 1), PositionInFlatTree(*span->firstChild(), 4))); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oof", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("fo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
foofoof^oo|
// So buffer = "oo" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*span->firstChild(), 4), PositionInFlatTree(*b->firstChild(), 2))); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("oof", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("fo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, FindBetweenPositionsSkippedNodes) { SetBodyContent( "
fooooo
"); Element* div = GetElementById("div"); Element* span = GetElementById("span"); Element* b = GetElementById("b"); Element* script = GetElementById("script"); Element* a = GetElementById("a"); //
^foofoo|foo // o
// So buffer = "foo" FindBuffer buffer(EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*div->firstChild()), PositionInFlatTree(*span->firstChild(), 3))); EXPECT_EQ(1u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("oof", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("fo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
foof^oofoo| // o
// So buffer = "oo" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*span->firstChild(), 1), PositionInFlatTree(*b->firstChild(), 2))); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
foof^oofoo| // o
// So buffer = "oo" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*span->firstChild(), 1), PositionInFlatTree(*script->firstChild(), 2))); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); //
foofoofoo| // o|
// So buffer = "o" buffer = FindBuffer( EphemeralRangeInFlatTree(PositionInFlatTree(*script->firstChild(), 1), PositionInFlatTree(*a->firstChild(), 1))); EXPECT_EQ(0u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("oo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("o", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("f", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, FindMatchInRange) { SetBodyContent("
foofoofoo
"); Element* div = GetElementById("div"); Element* a = GetElementById("a"); Element* b = GetElementById("b"); EphemeralRangeInFlatTree foo1 = EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*div->firstChild()), PositionInFlatTree::LastPositionInNode(*div->firstChild())); EphemeralRangeInFlatTree foo2 = EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*a->firstChild()), PositionInFlatTree(*a->firstChild(), 3)); EphemeralRangeInFlatTree foo3 = EphemeralRangeInFlatTree( PositionInFlatTree(*a->firstChild(), 3), PositionInFlatTree::LastPositionInNode(*b->firstChild())); //
^foofoofoo|
, forwards EphemeralRangeInFlatTree match = FindBuffer::FindMatchInRange( WholeDocumentRange(), "foo", kCaseInsensitive); EXPECT_EQ(foo1, match); //
f^oofoofoo|
, forwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree(PositionInFlatTree(*div->firstChild(), 1), LastPositionInDocument()), "foo", kCaseInsensitive); EXPECT_EQ(foo2, match); //
foo^foo|foo
, forwards match = FindBuffer::FindMatchInRange(foo2, "foo", kCaseInsensitive); EXPECT_EQ(foo2, match); //
foof^oof|oo
, forwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree( PositionInFlatTree(*a->firstChild(), 1), PositionInFlatTree::LastPositionInNode(*a->firstChild())), "foo", kCaseInsensitive); EXPECT_TRUE(match.IsNull()); //
foof^oofoo|
, forwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree(PositionInFlatTree(*a->firstChild(), 1), LastPositionInDocument()), "foo", kCaseInsensitive); EXPECT_EQ(foo3, match); //
^foofoofoo|
, backwards match = FindBuffer::FindMatchInRange(WholeDocumentRange(), "foo", kCaseInsensitive | kBackwards); EXPECT_EQ(foo3, match); //
^foofoofo|o
, backwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*div->firstChild()), PositionInFlatTree(*b->firstChild(), 1)), "foo", kCaseInsensitive | kBackwards); EXPECT_EQ(foo2, match); //
foo^foofo|o
, backwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*a->firstChild()), PositionInFlatTree(*b->firstChild(), 1)), "foo", kCaseInsensitive | kBackwards); EXPECT_EQ(foo2, match); //
foofoo^fo|o
, backwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree(PositionInFlatTree(*a->firstChild(), 3), PositionInFlatTree(*b->firstChild(), 1)), "foo", kCaseInsensitive | kBackwards); EXPECT_TRUE(match.IsNull()); //
^foofo|ofoo
, backwards match = FindBuffer::FindMatchInRange( EphemeralRangeInFlatTree( PositionInFlatTree::FirstPositionInNode(*div->firstChild()), PositionInFlatTree(*a->firstChild(), 2)), "foo", kCaseInsensitive | kBackwards); EXPECT_EQ(foo1, match); } class FindBufferBlockTest : public FindBufferTest, public testing::WithParamInterface {}; INSTANTIATE_TEST_SUITE_P(Blocks, FindBufferBlockTest, testing::Values("block", "table", "flow-root", "grid", "flex", "list-item")); TEST_P(FindBufferBlockTest, FindBlock) { SetBodyContent("text
block
span"); FindBuffer text_buffer(WholeDocumentRange()); EXPECT_EQ(GetElementById("block"), *text_buffer.PositionAfterBlock().ComputeContainerNode()); EXPECT_EQ( 1u, text_buffer.FindMatches("text", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, text_buffer.FindMatches("textblock", kCaseInsensitive) ->CountForTesting()); EXPECT_EQ(0u, text_buffer.FindMatches("text block", kCaseInsensitive) ->CountForTesting()); FindBuffer block_buffer(EphemeralRangeInFlatTree( text_buffer.PositionAfterBlock(), LastPositionInDocument())); EXPECT_EQ(GetElementById("span"), *block_buffer.PositionAfterBlock().ComputeContainerNode()); EXPECT_EQ( 1u, block_buffer.FindMatches("block", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, block_buffer.FindMatches("textblock", kCaseInsensitive) ->CountForTesting()); EXPECT_EQ(0u, block_buffer.FindMatches("text block", kCaseInsensitive) ->CountForTesting()); EXPECT_EQ(0u, block_buffer.FindMatches("blockspan", kCaseInsensitive) ->CountForTesting()); EXPECT_EQ(0u, block_buffer.FindMatches("block span", kCaseInsensitive) ->CountForTesting()); FindBuffer span_buffer(EphemeralRangeInFlatTree( block_buffer.PositionAfterBlock(), LastPositionInDocument())); EXPECT_TRUE(span_buffer.PositionAfterBlock().IsNull()); EXPECT_EQ( 1u, span_buffer.FindMatches("span", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, span_buffer.FindMatches("blockspan", kCaseInsensitive) ->CountForTesting()); EXPECT_EQ(0u, span_buffer.FindMatches("block span", kCaseInsensitive) ->CountForTesting()); } class FindBufferSeparatorTest : public FindBufferTest, public testing::WithParamInterface {}; INSTANTIATE_TEST_SUITE_P(Separators, FindBufferSeparatorTest, testing::Values("br", "hr", "legend", "meter", "object", "progress", "select", "video")); TEST_P(FindBufferSeparatorTest, FindSeparatedElements) { SetBodyContent("a<" + GetParam() + ">aa"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(0u, buffer.FindMatches("aa", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, WhiteSpaceCollapsingPreWrap) { SetBodyContent( " a \n b c d e " ""); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ( 1u, buffer.FindMatches("a b c d e ", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, WhiteSpaceCollapsingPre) { SetBodyContent("
a \n b
"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(1u, buffer.FindMatches("a", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("ab", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a\n b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a \nb", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a \n b", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, WhiteSpaceCollapsingPreLine) { SetBodyContent("
a \n b
"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(1u, buffer.FindMatches("a", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("ab", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a \n b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a\n b", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a \nb", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("a\nb", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, BidiTest) { SetBodyContent("foobar"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(1u, buffer.FindMatches("foobar", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, KanaSmallVsNormal) { SetBodyContent("や"); // Normal-sized や FindBuffer buffer(WholeDocumentRange()); // Should find normal-sized や EXPECT_EQ(1u, buffer.FindMatches("や", kCaseInsensitive)->CountForTesting()); // Should not find smalll-sized ゃ EXPECT_EQ(0u, buffer.FindMatches("ゃ", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, KanaDakuten) { SetBodyContent("びゃ"); // Hiragana bya FindBuffer buffer(WholeDocumentRange()); // Should find bi EXPECT_EQ(1u, buffer.FindMatches("び", kCaseInsensitive)->CountForTesting()); // Should find smalll-sized ゃ EXPECT_EQ(1u, buffer.FindMatches("ゃ", kCaseInsensitive)->CountForTesting()); // Should find bya EXPECT_EQ(1u, buffer.FindMatches("びゃ", kCaseInsensitive)->CountForTesting()); // Should not find hi EXPECT_EQ(0u, buffer.FindMatches("ひ", kCaseInsensitive)->CountForTesting()); // Should not find pi EXPECT_EQ(0u, buffer.FindMatches("ぴ", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, KanaHalfFull) { // Should treat hiragana, katakana, half width katakana as the same. // hiragana ra, half width katakana ki, full width katakana na SetBodyContent("らキナ"); FindBuffer buffer(WholeDocumentRange()); // Should find katakana ra EXPECT_EQ(1u, buffer.FindMatches("ラ", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ラ", kCaseInsensitive)->CountForTesting()); // Should find hiragana & katakana ki EXPECT_EQ(1u, buffer.FindMatches("き", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("キ", kCaseInsensitive)->CountForTesting()); // Should find hiragana & katakana na EXPECT_EQ(1u, buffer.FindMatches("な", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ナ", kCaseInsensitive)->CountForTesting()); // Should find whole word EXPECT_EQ(1u, buffer.FindMatches("らきな", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ラキナ", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ラキナ", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, WholeWordTest) { SetBodyContent("foo bar foobar 六本木"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(2u, buffer.FindMatches("foo", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("foo", kCaseInsensitive | kWholeWord) ->CountForTesting()); EXPECT_EQ(2u, buffer.FindMatches("bar", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("bar", kCaseInsensitive | kWholeWord) ->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("六", kCaseInsensitive | kWholeWord) ->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("本木", kCaseInsensitive | kWholeWord) ->CountForTesting()); } TEST_F(FindBufferTest, KanaDecomposed) { SetBodyContent("は ゛"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(0u, buffer.FindMatches("ば", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("は ゛", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(0u, buffer.FindMatches("バ ", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ハ ゛", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ハ ゙", kCaseInsensitive)->CountForTesting()); EXPECT_EQ(1u, buffer.FindMatches("ハ ゛", kCaseInsensitive)->CountForTesting()); } TEST_F(FindBufferTest, FindPlainTextInvalidTarget1) { static const char* body_content = "
foo bar test
"; SetBodyContent(body_content); // A lone lead surrogate (0xDA0A) example taken from fuzz-58. static const UChar kInvalid1[] = {0x1461u, 0x2130u, 0x129bu, 0xd711u, 0xd6feu, 0xccadu, 0x7064u, 0xd6a0u, 0x4e3bu, 0x03abu, 0x17dcu, 0xb8b7u, 0xbf55u, 0xfca0u, 0x07fau, 0x0427u, 0xda0au, 0}; FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches(String(kInvalid1), 0); EXPECT_TRUE(results->IsEmpty()); } TEST_F(FindBufferTest, FindPlainTextInvalidTarget2) { static const char* body_content = "
foo bar test
"; SetBodyContent(body_content); // A lone trailing surrogate (U+DC01). static const UChar kInvalid2[] = {0x1461u, 0x2130u, 0x129bu, 0xdc01u, 0xd6feu, 0xccadu, 0}; FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches(String(kInvalid2), 0); EXPECT_TRUE(results->IsEmpty()); } TEST_F(FindBufferTest, FindPlainTextInvalidTarget3) { static const char* body_content = "
foo bar test
"; SetBodyContent(body_content); // A trailing surrogate followed by a lead surrogate (U+DC03 U+D901). static const UChar kInvalid3[] = {0xd800u, 0xdc00u, 0x0061u, 0xdc03u, 0xd901u, 0xccadu, 0}; FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches(String(kInvalid3), 0); EXPECT_TRUE(results->IsEmpty()); } TEST_F(FindBufferTest, DisplayInline) { SetBodyContent("find"); FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches("find", 0); ASSERT_EQ(1u, results->CountForTesting()); EXPECT_EQ(FindBuffer::BufferMatchResult({0, 4}), results->front()); } TEST_F(FindBufferTest, DisplayBlock) { SetBodyContent("
fi
nd"); FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches("find", 0); ASSERT_EQ(0u, results->CountForTesting()) << "We should not match across block."; } TEST_F(FindBufferTest, DisplayContents) { SetBodyContent("
fi
nd"); FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches("find", 0); ASSERT_EQ(1u, results->CountForTesting()); EXPECT_EQ(FindBuffer::BufferMatchResult({0, 4}), results->front()); } TEST_F(FindBufferTest, WBRTest) { SetBodyContent("find and find"); FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches("find", 0); ASSERT_EQ(2u, results->CountForTesting()); } TEST_F(FindBufferTest, InputTest) { SetBodyContent("find and find"); FindBuffer buffer(WholeDocumentRange()); const auto results = buffer.FindMatches("find", 0); ASSERT_EQ(0u, results->CountForTesting()); } TEST_F(FindBufferTest, SelectMultipleTest) { SetBodyContent(""); FindBuffer buffer(WholeDocumentRange()); #if defined(OS_ANDROID) EXPECT_EQ(0u, buffer.FindMatches("find", 0)->CountForTesting()); #else EXPECT_EQ(1u, buffer.FindMatches("find", 0)->CountForTesting()); #endif // defined(OS_ANDROID) SetBodyContent(""); buffer = FindBuffer(WholeDocumentRange()); #if defined(OS_ANDROID) EXPECT_EQ(0u, buffer.FindMatches("find", 0)->CountForTesting()); #else EXPECT_EQ(1u, buffer.FindMatches("find", 0)->CountForTesting()); #endif // defined(OS_ANDROID) SetBodyContent(""); buffer = FindBuffer(WholeDocumentRange()); EXPECT_EQ(0u, buffer.FindMatches("find", 0)->CountForTesting()); } TEST_F(FindBufferTest, NullRange) { SetBodyContent("x
"); FindBuffer buffer(WholeDocumentRange()); EXPECT_EQ(0u, buffer.FindMatches("find", 0)->CountForTesting()); } } // namespace blink