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 "chrome/browser/chromeos/drive/search_metadata.h"
6
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/i18n/string_search.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/run_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
14 #include "chrome/browser/chromeos/drive/file_cache.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/drive/test_util.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace drive {
21 namespace internal {
22
23 namespace {
24
25 const int kDefaultAtMostNumMatches = 10;
26
27 // A simple wrapper for testing FindAndHighlightWrapper(). It just converts the
28 // query text parameter to FixedPatternStringSearchIgnoringCaseAndAccents.
FindAndHighlightWrapper(const std::string & text,const std::string & query_text,std::string * highlighted_text)29 bool FindAndHighlightWrapper(
30 const std::string& text,
31 const std::string& query_text,
32 std::string* highlighted_text) {
33 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents query(
34 base::UTF8ToUTF16(query_text));
35 return FindAndHighlight(text, &query, highlighted_text);
36 }
37
38 } // namespace
39
40 class SearchMetadataTest : public testing::Test {
41 protected:
SetUp()42 virtual void SetUp() OVERRIDE {
43 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
44 fake_free_disk_space_getter_.reset(new FakeFreeDiskSpaceGetter);
45
46 metadata_storage_.reset(new ResourceMetadataStorage(
47 temp_dir_.path(), base::MessageLoopProxy::current().get()));
48 ASSERT_TRUE(metadata_storage_->Initialize());
49
50 cache_.reset(new FileCache(metadata_storage_.get(),
51 temp_dir_.path(),
52 base::MessageLoopProxy::current().get(),
53 fake_free_disk_space_getter_.get()));
54 ASSERT_TRUE(cache_->Initialize());
55
56 resource_metadata_.reset(
57 new ResourceMetadata(metadata_storage_.get(),
58 cache_.get(),
59 base::MessageLoopProxy::current()));
60 ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
61
62 AddEntriesToMetadata();
63 }
64
AddEntriesToMetadata()65 void AddEntriesToMetadata() {
66 base::FilePath temp_file;
67 EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.path(), &temp_file));
68 const std::string temp_file_md5 = "md5";
69
70 ResourceEntry entry;
71 std::string local_id;
72
73 // drive/root
74 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
75 util::GetDriveMyDriveRootPath(), &local_id));
76 const std::string root_local_id = local_id;
77
78 // drive/root/Directory 1
79 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(GetDirectoryEntry(
80 "Directory 1", "dir1", 1, root_local_id), &local_id));
81 const std::string dir1_local_id = local_id;
82
83 // drive/root/Directory 1/SubDirectory File 1.txt
84 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(GetFileEntry(
85 "SubDirectory File 1.txt", "file1a", 2, dir1_local_id), &local_id));
86 EXPECT_EQ(FILE_ERROR_OK, cache_->Store(
87 local_id, temp_file_md5, temp_file, FileCache::FILE_OPERATION_COPY));
88
89 // drive/root/Directory 1/Shared To The Account Owner.txt
90 entry = GetFileEntry(
91 "Shared To The Account Owner.txt", "file1b", 3, dir1_local_id);
92 entry.set_shared_with_me(true);
93 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(entry, &local_id));
94
95 // drive/root/Directory 2 excludeDir-test
96 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(GetDirectoryEntry(
97 "Directory 2 excludeDir-test", "dir2", 4, root_local_id), &local_id));
98
99 // drive/root/Slash \xE2\x88\x95 in directory
100 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
101 GetDirectoryEntry("Slash \xE2\x88\x95 in directory", "dir3", 5,
102 root_local_id), &local_id));
103 const std::string dir3_local_id = local_id;
104
105 // drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt
106 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(GetFileEntry(
107 "Slash SubDir File.txt", "file3a", 6, dir3_local_id), &local_id));
108
109 // drive/root/File 2.txt
110 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(GetFileEntry(
111 "File 2.txt", "file2", 7, root_local_id), &local_id));
112 EXPECT_EQ(FILE_ERROR_OK, cache_->Store(
113 local_id, temp_file_md5, temp_file, FileCache::FILE_OPERATION_COPY));
114
115 // drive/root/Document 1 excludeDir-test
116 entry = GetFileEntry(
117 "Document 1 excludeDir-test", "doc1", 8, root_local_id);
118 entry.mutable_file_specific_info()->set_is_hosted_document(true);
119 entry.mutable_file_specific_info()->set_document_extension(".gdoc");
120 EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(entry, &local_id));
121
122 }
123
GetFileEntry(const std::string & name,const std::string & resource_id,int64 last_accessed,const std::string & parent_local_id)124 ResourceEntry GetFileEntry(const std::string& name,
125 const std::string& resource_id,
126 int64 last_accessed,
127 const std::string& parent_local_id) {
128 ResourceEntry entry;
129 entry.set_title(name);
130 entry.set_resource_id(resource_id);
131 entry.set_parent_local_id(parent_local_id);
132 entry.mutable_file_info()->set_last_accessed(last_accessed);
133 return entry;
134 }
135
GetDirectoryEntry(const std::string & name,const std::string & resource_id,int64 last_accessed,const std::string & parent_local_id)136 ResourceEntry GetDirectoryEntry(const std::string& name,
137 const std::string& resource_id,
138 int64 last_accessed,
139 const std::string& parent_local_id) {
140 ResourceEntry entry;
141 entry.set_title(name);
142 entry.set_resource_id(resource_id);
143 entry.set_parent_local_id(parent_local_id);
144 entry.mutable_file_info()->set_last_accessed(last_accessed);
145 entry.mutable_file_info()->set_is_directory(true);
146 return entry;
147 }
148
149 content::TestBrowserThreadBundle thread_bundle_;
150 base::ScopedTempDir temp_dir_;
151 scoped_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
152 scoped_ptr<ResourceMetadataStorage,
153 test_util::DestroyHelperForTests> metadata_storage_;
154 scoped_ptr<ResourceMetadata, test_util::DestroyHelperForTests>
155 resource_metadata_;
156 scoped_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
157 };
158
TEST_F(SearchMetadataTest,SearchMetadata_ZeroMatches)159 TEST_F(SearchMetadataTest, SearchMetadata_ZeroMatches) {
160 FileError error = FILE_ERROR_FAILED;
161 scoped_ptr<MetadataSearchResultVector> result;
162
163 SearchMetadata(base::MessageLoopProxy::current(),
164 resource_metadata_.get(),
165 "NonExistent",
166 SEARCH_METADATA_ALL,
167 kDefaultAtMostNumMatches,
168 google_apis::test_util::CreateCopyResultCallback(
169 &error, &result));
170 base::RunLoop().RunUntilIdle();
171 EXPECT_EQ(FILE_ERROR_OK, error);
172 ASSERT_TRUE(result);
173 ASSERT_EQ(0U, result->size());
174 }
175
TEST_F(SearchMetadataTest,SearchMetadata_RegularFile)176 TEST_F(SearchMetadataTest, SearchMetadata_RegularFile) {
177 FileError error = FILE_ERROR_FAILED;
178 scoped_ptr<MetadataSearchResultVector> result;
179
180 SearchMetadata(base::MessageLoopProxy::current(),
181 resource_metadata_.get(),
182 "SubDirectory File 1.txt",
183 SEARCH_METADATA_ALL,
184 kDefaultAtMostNumMatches,
185 google_apis::test_util::CreateCopyResultCallback(
186 &error, &result));
187 base::RunLoop().RunUntilIdle();
188 EXPECT_EQ(FILE_ERROR_OK, error);
189 ASSERT_TRUE(result);
190 ASSERT_EQ(1U, result->size());
191 EXPECT_EQ("drive/root/Directory 1/SubDirectory File 1.txt",
192 result->at(0).path.AsUTF8Unsafe());
193 }
194
195 // This test checks if |FindAndHighlightWrapper| does case-insensitive search.
196 // Tricker test cases for |FindAndHighlightWrapper| can be found below.
TEST_F(SearchMetadataTest,SearchMetadata_CaseInsensitiveSearch)197 TEST_F(SearchMetadataTest, SearchMetadata_CaseInsensitiveSearch) {
198 FileError error = FILE_ERROR_FAILED;
199 scoped_ptr<MetadataSearchResultVector> result;
200
201 // The query is all in lower case.
202 SearchMetadata(base::MessageLoopProxy::current(),
203 resource_metadata_.get(),
204 "subdirectory file 1.txt",
205 SEARCH_METADATA_ALL,
206 kDefaultAtMostNumMatches,
207 google_apis::test_util::CreateCopyResultCallback(
208 &error, &result));
209 base::RunLoop().RunUntilIdle();
210 EXPECT_EQ(FILE_ERROR_OK, error);
211 ASSERT_TRUE(result);
212 ASSERT_EQ(1U, result->size());
213 EXPECT_EQ("drive/root/Directory 1/SubDirectory File 1.txt",
214 result->at(0).path.AsUTF8Unsafe());
215 }
216
TEST_F(SearchMetadataTest,SearchMetadata_RegularFiles)217 TEST_F(SearchMetadataTest, SearchMetadata_RegularFiles) {
218 FileError error = FILE_ERROR_FAILED;
219 scoped_ptr<MetadataSearchResultVector> result;
220
221 SearchMetadata(base::MessageLoopProxy::current(),
222 resource_metadata_.get(),
223 "SubDir",
224 SEARCH_METADATA_ALL,
225 kDefaultAtMostNumMatches,
226 google_apis::test_util::CreateCopyResultCallback(
227 &error, &result));
228 base::RunLoop().RunUntilIdle();
229 EXPECT_EQ(FILE_ERROR_OK, error);
230 ASSERT_TRUE(result);
231 ASSERT_EQ(2U, result->size());
232
233 // All base names should contain "File". The results should be sorted by the
234 // last accessed time in descending order.
235 EXPECT_EQ("drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt",
236 result->at(0).path.AsUTF8Unsafe());
237 EXPECT_EQ("drive/root/Directory 1/SubDirectory File 1.txt",
238 result->at(1).path.AsUTF8Unsafe());
239 }
240
TEST_F(SearchMetadataTest,SearchMetadata_AtMostOneFile)241 TEST_F(SearchMetadataTest, SearchMetadata_AtMostOneFile) {
242 FileError error = FILE_ERROR_FAILED;
243 scoped_ptr<MetadataSearchResultVector> result;
244
245 // There are two files matching "SubDir" but only one file should be
246 // returned.
247 SearchMetadata(base::MessageLoopProxy::current(),
248 resource_metadata_.get(),
249 "SubDir",
250 SEARCH_METADATA_ALL,
251 1, // at_most_num_matches
252 google_apis::test_util::CreateCopyResultCallback(
253 &error, &result));
254 base::RunLoop().RunUntilIdle();
255 EXPECT_EQ(FILE_ERROR_OK, error);
256 ASSERT_TRUE(result);
257 ASSERT_EQ(1U, result->size());
258 EXPECT_EQ("drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt",
259 result->at(0).path.AsUTF8Unsafe());
260 }
261
TEST_F(SearchMetadataTest,SearchMetadata_Directory)262 TEST_F(SearchMetadataTest, SearchMetadata_Directory) {
263 FileError error = FILE_ERROR_FAILED;
264 scoped_ptr<MetadataSearchResultVector> result;
265
266 SearchMetadata(base::MessageLoopProxy::current(),
267 resource_metadata_.get(),
268 "Directory 1",
269 SEARCH_METADATA_ALL,
270 kDefaultAtMostNumMatches,
271 google_apis::test_util::CreateCopyResultCallback(
272 &error, &result));
273 base::RunLoop().RunUntilIdle();
274 EXPECT_EQ(FILE_ERROR_OK, error);
275 ASSERT_TRUE(result);
276 ASSERT_EQ(1U, result->size());
277 EXPECT_EQ("drive/root/Directory 1", result->at(0).path.AsUTF8Unsafe());
278 }
279
TEST_F(SearchMetadataTest,SearchMetadata_HostedDocument)280 TEST_F(SearchMetadataTest, SearchMetadata_HostedDocument) {
281 FileError error = FILE_ERROR_FAILED;
282 scoped_ptr<MetadataSearchResultVector> result;
283
284 SearchMetadata(base::MessageLoopProxy::current(),
285 resource_metadata_.get(),
286 "Document",
287 SEARCH_METADATA_ALL,
288 kDefaultAtMostNumMatches,
289 google_apis::test_util::CreateCopyResultCallback(
290 &error, &result));
291 base::RunLoop().RunUntilIdle();
292 EXPECT_EQ(FILE_ERROR_OK, error);
293 ASSERT_TRUE(result);
294 ASSERT_EQ(1U, result->size());
295
296 EXPECT_EQ("drive/root/Document 1 excludeDir-test.gdoc",
297 result->at(0).path.AsUTF8Unsafe());
298 }
299
TEST_F(SearchMetadataTest,SearchMetadata_ExcludeHostedDocument)300 TEST_F(SearchMetadataTest, SearchMetadata_ExcludeHostedDocument) {
301 FileError error = FILE_ERROR_FAILED;
302 scoped_ptr<MetadataSearchResultVector> result;
303
304 SearchMetadata(base::MessageLoopProxy::current(),
305 resource_metadata_.get(),
306 "Document",
307 SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS,
308 kDefaultAtMostNumMatches,
309 google_apis::test_util::CreateCopyResultCallback(
310 &error, &result));
311 base::RunLoop().RunUntilIdle();
312 EXPECT_EQ(FILE_ERROR_OK, error);
313 ASSERT_TRUE(result);
314 ASSERT_EQ(0U, result->size());
315 }
316
TEST_F(SearchMetadataTest,SearchMetadata_SharedWithMe)317 TEST_F(SearchMetadataTest, SearchMetadata_SharedWithMe) {
318 FileError error = FILE_ERROR_FAILED;
319 scoped_ptr<MetadataSearchResultVector> result;
320
321 SearchMetadata(base::MessageLoopProxy::current(),
322 resource_metadata_.get(),
323 "",
324 SEARCH_METADATA_SHARED_WITH_ME,
325 kDefaultAtMostNumMatches,
326 google_apis::test_util::CreateCopyResultCallback(
327 &error, &result));
328 base::RunLoop().RunUntilIdle();
329 EXPECT_EQ(FILE_ERROR_OK, error);
330 ASSERT_TRUE(result);
331 ASSERT_EQ(1U, result->size());
332 EXPECT_EQ("drive/root/Directory 1/Shared To The Account Owner.txt",
333 result->at(0).path.AsUTF8Unsafe());
334 }
335
TEST_F(SearchMetadataTest,SearchMetadata_FileAndDirectory)336 TEST_F(SearchMetadataTest, SearchMetadata_FileAndDirectory) {
337 FileError error = FILE_ERROR_FAILED;
338 scoped_ptr<MetadataSearchResultVector> result;
339
340 SearchMetadata(base::MessageLoopProxy::current(),
341 resource_metadata_.get(),
342 "excludeDir-test",
343 SEARCH_METADATA_ALL,
344 kDefaultAtMostNumMatches,
345 google_apis::test_util::CreateCopyResultCallback(
346 &error, &result));
347
348 base::RunLoop().RunUntilIdle();
349 EXPECT_EQ(FILE_ERROR_OK, error);
350 ASSERT_TRUE(result);
351 ASSERT_EQ(2U, result->size());
352
353 EXPECT_EQ("drive/root/Document 1 excludeDir-test.gdoc",
354 result->at(0).path.AsUTF8Unsafe());
355 EXPECT_EQ("drive/root/Directory 2 excludeDir-test",
356 result->at(1).path.AsUTF8Unsafe());
357 }
358
TEST_F(SearchMetadataTest,SearchMetadata_ExcludeDirectory)359 TEST_F(SearchMetadataTest, SearchMetadata_ExcludeDirectory) {
360 FileError error = FILE_ERROR_FAILED;
361 scoped_ptr<MetadataSearchResultVector> result;
362
363 SearchMetadata(base::MessageLoopProxy::current(),
364 resource_metadata_.get(),
365 "excludeDir-test",
366 SEARCH_METADATA_EXCLUDE_DIRECTORIES,
367 kDefaultAtMostNumMatches,
368 google_apis::test_util::CreateCopyResultCallback(
369 &error, &result));
370
371 base::RunLoop().RunUntilIdle();
372 EXPECT_EQ(FILE_ERROR_OK, error);
373 ASSERT_TRUE(result);
374 ASSERT_EQ(1U, result->size());
375
376 EXPECT_EQ("drive/root/Document 1 excludeDir-test.gdoc",
377 result->at(0).path.AsUTF8Unsafe());
378 }
379
380 // "drive", "drive/root", "drive/other" should be excluded.
TEST_F(SearchMetadataTest,SearchMetadata_ExcludeSpecialDirectories)381 TEST_F(SearchMetadataTest, SearchMetadata_ExcludeSpecialDirectories) {
382 const char* kQueries[] = { "drive", "root", "other" };
383 for (size_t i = 0; i < arraysize(kQueries); ++i) {
384 FileError error = FILE_ERROR_FAILED;
385 scoped_ptr<MetadataSearchResultVector> result;
386
387 const std::string query = kQueries[i];
388 SearchMetadata(base::MessageLoopProxy::current(),
389 resource_metadata_.get(),
390 query,
391 SEARCH_METADATA_ALL,
392 kDefaultAtMostNumMatches,
393 google_apis::test_util::CreateCopyResultCallback(
394 &error, &result));
395
396 base::RunLoop().RunUntilIdle();
397 EXPECT_EQ(FILE_ERROR_OK, error);
398 ASSERT_TRUE(result);
399 ASSERT_TRUE(result->empty()) << ": " << query << " should not match";
400 }
401 }
402
TEST_F(SearchMetadataTest,SearchMetadata_Offline)403 TEST_F(SearchMetadataTest, SearchMetadata_Offline) {
404 FileError error = FILE_ERROR_FAILED;
405 scoped_ptr<MetadataSearchResultVector> result;
406
407 SearchMetadata(base::MessageLoopProxy::current(),
408 resource_metadata_.get(),
409 "",
410 SEARCH_METADATA_OFFLINE,
411 kDefaultAtMostNumMatches,
412 google_apis::test_util::CreateCopyResultCallback(
413 &error, &result));
414 base::RunLoop().RunUntilIdle();
415 EXPECT_EQ(FILE_ERROR_OK, error);
416 ASSERT_EQ(3U, result->size());
417
418 // This is not included in the cache but is a hosted document.
419 EXPECT_EQ("drive/root/Document 1 excludeDir-test.gdoc",
420 result->at(0).path.AsUTF8Unsafe());
421
422 EXPECT_EQ("drive/root/File 2.txt",
423 result->at(1).path.AsUTF8Unsafe());
424 EXPECT_EQ("drive/root/Directory 1/SubDirectory File 1.txt",
425 result->at(2).path.AsUTF8Unsafe());
426 }
427
TEST(SearchMetadataSimpleTest,FindAndHighlight_ZeroMatches)428 TEST(SearchMetadataSimpleTest, FindAndHighlight_ZeroMatches) {
429 std::string highlighted_text;
430 EXPECT_FALSE(FindAndHighlightWrapper("text", "query", &highlighted_text));
431 }
432
TEST(SearchMetadataSimpleTest,FindAndHighlight_EmptyText)433 TEST(SearchMetadataSimpleTest, FindAndHighlight_EmptyText) {
434 std::string highlighted_text;
435 EXPECT_FALSE(FindAndHighlightWrapper("", "query", &highlighted_text));
436 }
437
TEST(SearchMetadataSimpleTest,FindAndHighlight_FullMatch)438 TEST(SearchMetadataSimpleTest, FindAndHighlight_FullMatch) {
439 std::string highlighted_text;
440 EXPECT_TRUE(FindAndHighlightWrapper("hello", "hello", &highlighted_text));
441 EXPECT_EQ("<b>hello</b>", highlighted_text);
442 }
443
TEST(SearchMetadataSimpleTest,FindAndHighlight_StartWith)444 TEST(SearchMetadataSimpleTest, FindAndHighlight_StartWith) {
445 std::string highlighted_text;
446 EXPECT_TRUE(FindAndHighlightWrapper("hello, world", "hello",
447 &highlighted_text));
448 EXPECT_EQ("<b>hello</b>, world", highlighted_text);
449 }
450
TEST(SearchMetadataSimpleTest,FindAndHighlight_EndWith)451 TEST(SearchMetadataSimpleTest, FindAndHighlight_EndWith) {
452 std::string highlighted_text;
453 EXPECT_TRUE(FindAndHighlightWrapper("hello, world", "world",
454 &highlighted_text));
455 EXPECT_EQ("hello, <b>world</b>", highlighted_text);
456 }
457
TEST(SearchMetadataSimpleTest,FindAndHighlight_InTheMiddle)458 TEST(SearchMetadataSimpleTest, FindAndHighlight_InTheMiddle) {
459 std::string highlighted_text;
460 EXPECT_TRUE(FindAndHighlightWrapper("yo hello, world", "hello",
461 &highlighted_text));
462 EXPECT_EQ("yo <b>hello</b>, world", highlighted_text);
463 }
464
TEST(SearchMetadataSimpleTest,FindAndHighlight_MultipeMatches)465 TEST(SearchMetadataSimpleTest, FindAndHighlight_MultipeMatches) {
466 std::string highlighted_text;
467 EXPECT_TRUE(FindAndHighlightWrapper("yoyoyoyoy", "yoy", &highlighted_text));
468 // Only the first match is highlighted.
469 EXPECT_EQ("<b>yoy</b>oyoyoy", highlighted_text);
470 }
471
TEST(SearchMetadataSimpleTest,FindAndHighlight_IgnoreCase)472 TEST(SearchMetadataSimpleTest, FindAndHighlight_IgnoreCase) {
473 std::string highlighted_text;
474 EXPECT_TRUE(FindAndHighlightWrapper("HeLLo", "hello", &highlighted_text));
475 EXPECT_EQ("<b>HeLLo</b>", highlighted_text);
476 }
477
TEST(SearchMetadataSimpleTest,FindAndHighlight_IgnoreCaseNonASCII)478 TEST(SearchMetadataSimpleTest, FindAndHighlight_IgnoreCaseNonASCII) {
479 std::string highlighted_text;
480
481 // Case and accent ignorance in Greek. Find "socra" in "Socra'tes".
482 EXPECT_TRUE(FindAndHighlightWrapper(
483 "\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC\xCF\x84\xCE\xB7\xCF\x82",
484 "\xCF\x83\xCF\x89\xCE\xBA\xCF\x81\xCE\xB1", &highlighted_text));
485 EXPECT_EQ(
486 "<b>\xCE\xA3\xCF\x89\xCE\xBA\xCF\x81\xCE\xAC</b>\xCF\x84\xCE\xB7\xCF\x82",
487 highlighted_text);
488
489 // In Japanese characters.
490 // Find Hiragana "pi" + "(small)ya" in Katakana "hi" + semi-voiced-mark + "ya"
491 EXPECT_TRUE(FindAndHighlightWrapper(
492 "\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83\xE3\x83\xBC",
493 "\xE3\x83\x94\xE3\x83\xA4",
494 &highlighted_text));
495 EXPECT_EQ(
496 "<b>\xE3\x81\xB2\xE3\x82\x9A\xE3\x82\x83</b>\xE3\x83\xBC",
497 highlighted_text);
498 }
499
TEST(SearchMetadataSimpleTest,MultiTextBySingleQuery)500 TEST(SearchMetadataSimpleTest, MultiTextBySingleQuery) {
501 base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents query(
502 base::UTF8ToUTF16("hello"));
503
504 std::string highlighted_text;
505 EXPECT_TRUE(FindAndHighlight("hello", &query, &highlighted_text));
506 EXPECT_EQ("<b>hello</b>", highlighted_text);
507 EXPECT_FALSE(FindAndHighlight("goodbye", &query, &highlighted_text));
508 EXPECT_TRUE(FindAndHighlight("1hello2", &query, &highlighted_text));
509 EXPECT_EQ("1<b>hello</b>2", highlighted_text);
510 }
511
TEST(SearchMetadataSimpleTest,FindAndHighlight_MetaChars)512 TEST(SearchMetadataSimpleTest, FindAndHighlight_MetaChars) {
513 std::string highlighted_text;
514 EXPECT_TRUE(FindAndHighlightWrapper("<hello>", "hello", &highlighted_text));
515 EXPECT_EQ("<<b>hello</b>>", highlighted_text);
516 }
517
TEST(SearchMetadataSimpleTest,FindAndHighlight_MoreMetaChars)518 TEST(SearchMetadataSimpleTest, FindAndHighlight_MoreMetaChars) {
519 std::string highlighted_text;
520 EXPECT_TRUE(FindAndHighlightWrapper("a&b&c&d", "b&c", &highlighted_text));
521 EXPECT_EQ("a&<b>b&c</b>&d", highlighted_text);
522 }
523
524 } // namespace internal
525 } // namespace drive
526