1 // Copyright (c) 2013 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 "components/drive/chromeos/search_metadata.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <vector>
12 
13 #include "base/i18n/string_search.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace drive {
18 namespace internal {
19 
20 namespace {
21 
22 // A simple wrapper for testing FindAndHighlightWrapper(). It just converts the
23 // query text parameter to FixedPatternStringSearchIgnoringCaseAndAccents.
FindAndHighlightWrapper(const std::string & text,const std::string & query_text,std::string * highlighted_text)24 bool FindAndHighlightWrapper(
25     const std::string& text,
26     const std::string& query_text,
27     std::string* highlighted_text) {
28   std::vector<std::unique_ptr<
29       base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>
30       queries;
31   queries.push_back(std::make_unique<
32                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
33       base::UTF8ToUTF16(query_text)));
34   return FindAndHighlight(text, queries, highlighted_text);
35 }
36 
37 }  // namespace
38 
TEST(SearchMetadataSimpleTest,FindAndHighlight_ZeroMatches)39 TEST(SearchMetadataSimpleTest, FindAndHighlight_ZeroMatches) {
40   std::string highlighted_text;
41   EXPECT_FALSE(FindAndHighlightWrapper("text", "query", &highlighted_text));
42 }
43 
TEST(SearchMetadataSimpleTest,FindAndHighlight_EmptyText)44 TEST(SearchMetadataSimpleTest, FindAndHighlight_EmptyText) {
45   std::string highlighted_text;
46   EXPECT_FALSE(FindAndHighlightWrapper("", "query", &highlighted_text));
47 }
48 
TEST(SearchMetadataSimpleTest,FindAndHighlight_EmptyQuery)49 TEST(SearchMetadataSimpleTest, FindAndHighlight_EmptyQuery) {
50   std::vector<std::unique_ptr<
51       base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>
52       queries;
53 
54   std::string highlighted_text;
55   EXPECT_TRUE(FindAndHighlight("hello", queries, &highlighted_text));
56   EXPECT_EQ("hello", highlighted_text);
57 }
58 
TEST(SearchMetadataSimpleTest,FindAndHighlight_FullMatch)59 TEST(SearchMetadataSimpleTest, FindAndHighlight_FullMatch) {
60   std::string highlighted_text;
61   EXPECT_TRUE(FindAndHighlightWrapper("hello", "hello", &highlighted_text));
62   EXPECT_EQ("<b>hello</b>", highlighted_text);
63 }
64 
TEST(SearchMetadataSimpleTest,FindAndHighlight_StartWith)65 TEST(SearchMetadataSimpleTest, FindAndHighlight_StartWith) {
66   std::string highlighted_text;
67   EXPECT_TRUE(FindAndHighlightWrapper("hello, world", "hello",
68                                      &highlighted_text));
69   EXPECT_EQ("<b>hello</b>, world", highlighted_text);
70 }
71 
TEST(SearchMetadataSimpleTest,FindAndHighlight_EndWith)72 TEST(SearchMetadataSimpleTest, FindAndHighlight_EndWith) {
73   std::string highlighted_text;
74   EXPECT_TRUE(FindAndHighlightWrapper("hello, world", "world",
75                                      &highlighted_text));
76   EXPECT_EQ("hello, <b>world</b>", highlighted_text);
77 }
78 
TEST(SearchMetadataSimpleTest,FindAndHighlight_InTheMiddle)79 TEST(SearchMetadataSimpleTest, FindAndHighlight_InTheMiddle) {
80   std::string highlighted_text;
81   EXPECT_TRUE(FindAndHighlightWrapper("yo hello, world", "hello",
82                                      &highlighted_text));
83   EXPECT_EQ("yo <b>hello</b>, world", highlighted_text);
84 }
85 
TEST(SearchMetadataSimpleTest,FindAndHighlight_MultipeMatches)86 TEST(SearchMetadataSimpleTest, FindAndHighlight_MultipeMatches) {
87   std::string highlighted_text;
88   EXPECT_TRUE(FindAndHighlightWrapper("yoyoyoyoy", "yoy", &highlighted_text));
89   // Only the first match is highlighted.
90   EXPECT_EQ("<b>yoy</b>oyoyoy", highlighted_text);
91 }
92 
TEST(SearchMetadataSimpleTest,FindAndHighlight_IgnoreCase)93 TEST(SearchMetadataSimpleTest, FindAndHighlight_IgnoreCase) {
94   std::string highlighted_text;
95   EXPECT_TRUE(FindAndHighlightWrapper("HeLLo", "hello", &highlighted_text));
96   EXPECT_EQ("<b>HeLLo</b>", highlighted_text);
97 }
98 
TEST(SearchMetadataSimpleTest,FindAndHighlight_IgnoreCaseNonASCII)99 TEST(SearchMetadataSimpleTest, FindAndHighlight_IgnoreCaseNonASCII) {
100   std::string highlighted_text;
101 
102   // Case and accent ignorance in Greek. Find "socra" in "Socra'tes".
103   EXPECT_TRUE(FindAndHighlightWrapper(
104       "\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC\xCF\x84\xCE\xB7\xCF\x82",
105       "\xCF\x83\xCF\x89\xCE\xBA\xCF\x81\xCE\xB1", &highlighted_text));
106   EXPECT_EQ(
107       "<b>\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC</b>\xCF\x84\xCE\xB7\xCF\x82",
108       highlighted_text);
109 
110   // In Japanese characters.
111   // Find Hiragana "pi" + "(small)ya" in Katakana "hi" + semi-voiced-mark + "ya"
112   EXPECT_TRUE(FindAndHighlightWrapper(
113       "\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83\xE3\x83\xBC",
114       "\xE3\x83\x94\xE3\x83\xA4",
115       &highlighted_text));
116   EXPECT_EQ(
117       "<b>\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83</b>\xE3\x83\xBC",
118       highlighted_text);
119 }
120 
TEST(SearchMetadataSimpleTest,MultiTextBySingleQuery)121 TEST(SearchMetadataSimpleTest, MultiTextBySingleQuery) {
122   std::vector<std::unique_ptr<
123       base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>
124       queries;
125   queries.push_back(std::make_unique<
126                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
127       base::UTF8ToUTF16("hello")));
128 
129   std::string highlighted_text;
130   EXPECT_TRUE(FindAndHighlight("hello", queries, &highlighted_text));
131   EXPECT_EQ("<b>hello</b>", highlighted_text);
132   EXPECT_FALSE(FindAndHighlight("goodbye", queries, &highlighted_text));
133   EXPECT_TRUE(FindAndHighlight("1hello2", queries, &highlighted_text));
134   EXPECT_EQ("1<b>hello</b>2", highlighted_text);
135 }
136 
TEST(SearchMetadataSimpleTest,FindAndHighlight_MetaChars)137 TEST(SearchMetadataSimpleTest, FindAndHighlight_MetaChars) {
138   std::string highlighted_text;
139   EXPECT_TRUE(FindAndHighlightWrapper("<hello>", "hello", &highlighted_text));
140   EXPECT_EQ("&lt;<b>hello</b>&gt;", highlighted_text);
141 }
142 
TEST(SearchMetadataSimpleTest,FindAndHighlight_MoreMetaChars)143 TEST(SearchMetadataSimpleTest, FindAndHighlight_MoreMetaChars) {
144   std::string highlighted_text;
145   EXPECT_TRUE(FindAndHighlightWrapper("a&b&c&d", "b&c", &highlighted_text));
146   EXPECT_EQ("a&amp;<b>b&amp;c</b>&amp;d", highlighted_text);
147 }
148 
TEST(SearchMetadataSimpleTest,FindAndHighlight_SurrogatePair)149 TEST(SearchMetadataSimpleTest, FindAndHighlight_SurrogatePair) {
150   std::string highlighted_text;
151   // \xF0\x9F\x98\x81 (U+1F601) is a surrogate pair for smile icon of emoji.
152   EXPECT_TRUE(FindAndHighlightWrapper("hi\xF0\x9F\x98\x81hello",
153                                       "i\xF0\x9F\x98\x81", &highlighted_text));
154   EXPECT_EQ("h<b>i\xF0\x9F\x98\x81</b>hello", highlighted_text);
155 }
156 
TEST(SearchMetadataSimpleTest,FindAndHighlight_MultipleQueries)157 TEST(SearchMetadataSimpleTest, FindAndHighlight_MultipleQueries) {
158   std::vector<std::unique_ptr<
159       base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>
160       queries;
161   queries.push_back(std::make_unique<
162                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
163       base::UTF8ToUTF16("hello")));
164   queries.push_back(std::make_unique<
165                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
166       base::UTF8ToUTF16("good")));
167 
168   std::string highlighted_text;
169   EXPECT_TRUE(
170       FindAndHighlight("good morning, hello", queries, &highlighted_text));
171   EXPECT_EQ("<b>good</b> morning, <b>hello</b>", highlighted_text);
172 }
173 
TEST(SearchMetadataSimpleTest,FindAndHighlight_OverlappingHighlights)174 TEST(SearchMetadataSimpleTest, FindAndHighlight_OverlappingHighlights) {
175   std::vector<std::unique_ptr<
176       base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>>
177       queries;
178   queries.push_back(std::make_unique<
179                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
180       base::UTF8ToUTF16("morning")));
181   queries.push_back(std::make_unique<
182                     base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents>(
183       base::UTF8ToUTF16("ing,")));
184 
185   std::string highlighted_text;
186   EXPECT_TRUE(
187       FindAndHighlight("good morning, hello", queries, &highlighted_text));
188   EXPECT_EQ("good <b>morning,</b> hello", highlighted_text);
189 }
190 
191 }  // namespace internal
192 }  // namespace drive
193