| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/bookmarks/core/browser/bookmark_utils.h" | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/message_loop/message_loop.h" | |
| 10 #include "base/strings/utf_string_conversions.h" | |
| 11 #include "components/bookmarks/core/browser/base_bookmark_model_observer.h" | |
| 12 #include "components/bookmarks/core/browser/bookmark_model.h" | |
| 13 #include "components/bookmarks/core/browser/bookmark_node_data.h" | |
| 14 #include "components/bookmarks/core/test/test_bookmark_client.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "ui/base/clipboard/clipboard.h" | |
| 17 #include "ui/base/clipboard/scoped_clipboard_writer.h" | |
| 18 | |
| 19 using base::ASCIIToUTF16; | |
| 20 using std::string; | |
| 21 | |
| 22 namespace bookmark_utils { | |
| 23 namespace { | |
| 24 | |
| 25 class BookmarkUtilsTest : public testing::Test, | |
| 26 public BaseBookmarkModelObserver { | |
| 27 public: | |
| 28 BookmarkUtilsTest() | |
| 29 : grouped_changes_beginning_count_(0), | |
| 30 grouped_changes_ended_count_(0) {} | |
| 31 virtual ~BookmarkUtilsTest() {} | |
| 32 | |
| 33 // Copy and paste is not yet supported on iOS. http://crbug.com/228147 | |
| 34 #if !defined(OS_IOS) | |
| 35 virtual void TearDown() OVERRIDE { | |
| 36 ui::Clipboard::DestroyClipboardForCurrentThread(); | |
| 37 } | |
| 38 #endif // !defined(OS_IOS) | |
| 39 | |
| 40 // Certain user actions require multiple changes to the bookmark model, | |
| 41 // however these modifications need to be atomic for the undo framework. The | |
| 42 // BaseBookmarkModelObserver is used to inform the boundaries of the user | |
| 43 // action. For example, when multiple bookmarks are cut to the clipboard we | |
| 44 // expect one call each to GroupedBookmarkChangesBeginning/Ended. | |
| 45 void ExpectGroupedChangeCount(int expected_beginning_count, | |
| 46 int expected_ended_count) { | |
| 47 // The undo framework is not used under Android. Thus the group change | |
| 48 // events will not be fired and so should not be tested for Android. | |
| 49 #if !defined(OS_ANDROID) | |
| 50 EXPECT_EQ(grouped_changes_beginning_count_, expected_beginning_count); | |
| 51 EXPECT_EQ(grouped_changes_ended_count_, expected_ended_count); | |
| 52 #endif | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 // BaseBookmarkModelObserver: | |
| 57 virtual void BookmarkModelChanged() OVERRIDE {} | |
| 58 | |
| 59 virtual void GroupedBookmarkChangesBeginning(BookmarkModel* model) OVERRIDE { | |
| 60 ++grouped_changes_beginning_count_; | |
| 61 } | |
| 62 | |
| 63 virtual void GroupedBookmarkChangesEnded(BookmarkModel* model) OVERRIDE { | |
| 64 ++grouped_changes_ended_count_; | |
| 65 } | |
| 66 | |
| 67 int grouped_changes_beginning_count_; | |
| 68 int grouped_changes_ended_count_; | |
| 69 | |
| 70 // Clipboard requires a message loop. | |
| 71 base::MessageLoopForUI loop_; | |
| 72 | |
| 73 DISALLOW_COPY_AND_ASSIGN(BookmarkUtilsTest); | |
| 74 }; | |
| 75 | |
| 76 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesWordPhraseQuery) { | |
| 77 test::TestBookmarkClient client; | |
| 78 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 79 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
| 80 0, | |
| 81 ASCIIToUTF16("foo bar"), | |
| 82 GURL("http://www.google.com")); | |
| 83 const BookmarkNode* node2 = model->AddURL(model->other_node(), | |
| 84 0, | |
| 85 ASCIIToUTF16("baz buz"), | |
| 86 GURL("http://www.cnn.com")); | |
| 87 const BookmarkNode* folder1 = | |
| 88 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("foo")); | |
| 89 std::vector<const BookmarkNode*> nodes; | |
| 90 QueryFields query; | |
| 91 query.word_phrase_query.reset(new base::string16); | |
| 92 // No nodes are returned for empty string. | |
| 93 *query.word_phrase_query = ASCIIToUTF16(""); | |
| 94 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 95 EXPECT_TRUE(nodes.empty()); | |
| 96 nodes.clear(); | |
| 97 | |
| 98 // No nodes are returned for space-only string. | |
| 99 *query.word_phrase_query = ASCIIToUTF16(" "); | |
| 100 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 101 EXPECT_TRUE(nodes.empty()); | |
| 102 nodes.clear(); | |
| 103 | |
| 104 // Node "foo bar" and folder "foo" are returned in search results. | |
| 105 *query.word_phrase_query = ASCIIToUTF16("foo"); | |
| 106 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 107 ASSERT_EQ(2U, nodes.size()); | |
| 108 EXPECT_TRUE(nodes[0] == folder1); | |
| 109 EXPECT_TRUE(nodes[1] == node1); | |
| 110 nodes.clear(); | |
| 111 | |
| 112 // Ensure url matches return in search results. | |
| 113 *query.word_phrase_query = ASCIIToUTF16("cnn"); | |
| 114 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 115 ASSERT_EQ(1U, nodes.size()); | |
| 116 EXPECT_TRUE(nodes[0] == node2); | |
| 117 nodes.clear(); | |
| 118 | |
| 119 // Ensure folder "foo" is not returned in more specific search. | |
| 120 *query.word_phrase_query = ASCIIToUTF16("foo bar"); | |
| 121 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 122 ASSERT_EQ(1U, nodes.size()); | |
| 123 EXPECT_TRUE(nodes[0] == node1); | |
| 124 nodes.clear(); | |
| 125 | |
| 126 // Bookmark Bar and Other Bookmarks are not returned in search results. | |
| 127 *query.word_phrase_query = ASCIIToUTF16("Bookmark"); | |
| 128 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 129 ASSERT_EQ(0U, nodes.size()); | |
| 130 nodes.clear(); | |
| 131 } | |
| 132 | |
| 133 // Check exact matching against a URL query. | |
| 134 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesUrl) { | |
| 135 test::TestBookmarkClient client; | |
| 136 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 137 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
| 138 0, | |
| 139 ASCIIToUTF16("Google"), | |
| 140 GURL("https://www.google.com/")); | |
| 141 model->AddURL(model->other_node(), | |
| 142 0, | |
| 143 ASCIIToUTF16("Google Calendar"), | |
| 144 GURL("https://www.google.com/calendar")); | |
| 145 | |
| 146 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
| 147 | |
| 148 std::vector<const BookmarkNode*> nodes; | |
| 149 QueryFields query; | |
| 150 query.url.reset(new base::string16); | |
| 151 *query.url = ASCIIToUTF16("https://www.google.com/"); | |
| 152 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 153 ASSERT_EQ(1U, nodes.size()); | |
| 154 EXPECT_TRUE(nodes[0] == node1); | |
| 155 nodes.clear(); | |
| 156 | |
| 157 *query.url = ASCIIToUTF16("calendar"); | |
| 158 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 159 ASSERT_EQ(0U, nodes.size()); | |
| 160 nodes.clear(); | |
| 161 | |
| 162 // Empty URL should not match folders. | |
| 163 *query.url = ASCIIToUTF16(""); | |
| 164 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 165 ASSERT_EQ(0U, nodes.size()); | |
| 166 nodes.clear(); | |
| 167 } | |
| 168 | |
| 169 // Check exact matching against a title query. | |
| 170 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesTitle) { | |
| 171 test::TestBookmarkClient client; | |
| 172 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 173 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
| 174 0, | |
| 175 ASCIIToUTF16("Google"), | |
| 176 GURL("https://www.google.com/")); | |
| 177 model->AddURL(model->other_node(), | |
| 178 0, | |
| 179 ASCIIToUTF16("Google Calendar"), | |
| 180 GURL("https://www.google.com/calendar")); | |
| 181 | |
| 182 const BookmarkNode* folder1 = | |
| 183 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
| 184 | |
| 185 std::vector<const BookmarkNode*> nodes; | |
| 186 QueryFields query; | |
| 187 query.title.reset(new base::string16); | |
| 188 *query.title = ASCIIToUTF16("Google"); | |
| 189 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 190 ASSERT_EQ(1U, nodes.size()); | |
| 191 EXPECT_TRUE(nodes[0] == node1); | |
| 192 nodes.clear(); | |
| 193 | |
| 194 *query.title = ASCIIToUTF16("Calendar"); | |
| 195 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 196 ASSERT_EQ(0U, nodes.size()); | |
| 197 nodes.clear(); | |
| 198 | |
| 199 // Title should match folders. | |
| 200 *query.title = ASCIIToUTF16("Folder"); | |
| 201 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 202 ASSERT_EQ(1U, nodes.size()); | |
| 203 EXPECT_TRUE(nodes[0] == folder1); | |
| 204 nodes.clear(); | |
| 205 } | |
| 206 | |
| 207 // Check matching against a query with multiple predicates. | |
| 208 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesConjunction) { | |
| 209 test::TestBookmarkClient client; | |
| 210 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 211 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
| 212 0, | |
| 213 ASCIIToUTF16("Google"), | |
| 214 GURL("https://www.google.com/")); | |
| 215 model->AddURL(model->other_node(), | |
| 216 0, | |
| 217 ASCIIToUTF16("Google Calendar"), | |
| 218 GURL("https://www.google.com/calendar")); | |
| 219 | |
| 220 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
| 221 | |
| 222 std::vector<const BookmarkNode*> nodes; | |
| 223 QueryFields query; | |
| 224 | |
| 225 // Test all fields matching. | |
| 226 query.word_phrase_query.reset(new base::string16(ASCIIToUTF16("www"))); | |
| 227 query.url.reset(new base::string16(ASCIIToUTF16("https://www.google.com/"))); | |
| 228 query.title.reset(new base::string16(ASCIIToUTF16("Google"))); | |
| 229 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 230 ASSERT_EQ(1U, nodes.size()); | |
| 231 EXPECT_TRUE(nodes[0] == node1); | |
| 232 nodes.clear(); | |
| 233 | |
| 234 scoped_ptr<base::string16>* fields[] = { | |
| 235 &query.word_phrase_query, &query.url, &query.title }; | |
| 236 | |
| 237 // Test two fields matching. | |
| 238 for (size_t i = 0; i < arraysize(fields); i++) { | |
| 239 scoped_ptr<base::string16> original_value(fields[i]->release()); | |
| 240 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 241 ASSERT_EQ(1U, nodes.size()); | |
| 242 EXPECT_TRUE(nodes[0] == node1); | |
| 243 nodes.clear(); | |
| 244 fields[i]->reset(original_value.release()); | |
| 245 } | |
| 246 | |
| 247 // Test two fields matching with one non-matching field. | |
| 248 for (size_t i = 0; i < arraysize(fields); i++) { | |
| 249 scoped_ptr<base::string16> original_value(fields[i]->release()); | |
| 250 fields[i]->reset(new base::string16(ASCIIToUTF16("fjdkslafjkldsa"))); | |
| 251 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
| 252 ASSERT_EQ(0U, nodes.size()); | |
| 253 nodes.clear(); | |
| 254 fields[i]->reset(original_value.release()); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 // Copy and paste is not yet supported on iOS. http://crbug.com/228147 | |
| 259 #if !defined(OS_IOS) | |
| 260 TEST_F(BookmarkUtilsTest, CopyPaste) { | |
| 261 test::TestBookmarkClient client; | |
| 262 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 263 const BookmarkNode* node = model->AddURL(model->other_node(), | |
| 264 0, | |
| 265 ASCIIToUTF16("foo bar"), | |
| 266 GURL("http://www.google.com")); | |
| 267 | |
| 268 // Copy a node to the clipboard. | |
| 269 std::vector<const BookmarkNode*> nodes; | |
| 270 nodes.push_back(node); | |
| 271 CopyToClipboard(model.get(), nodes, false); | |
| 272 | |
| 273 // And make sure we can paste a bookmark from the clipboard. | |
| 274 EXPECT_TRUE(CanPasteFromClipboard(model->bookmark_bar_node())); | |
| 275 | |
| 276 // Write some text to the clipboard. | |
| 277 { | |
| 278 ui::ScopedClipboardWriter clipboard_writer( | |
| 279 ui::Clipboard::GetForCurrentThread(), | |
| 280 ui::CLIPBOARD_TYPE_COPY_PASTE); | |
| 281 clipboard_writer.WriteText(ASCIIToUTF16("foo")); | |
| 282 } | |
| 283 | |
| 284 // Now we shouldn't be able to paste from the clipboard. | |
| 285 EXPECT_FALSE(CanPasteFromClipboard(model->bookmark_bar_node())); | |
| 286 } | |
| 287 | |
| 288 TEST_F(BookmarkUtilsTest, CutToClipboard) { | |
| 289 test::TestBookmarkClient client; | |
| 290 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 291 model->AddObserver(this); | |
| 292 | |
| 293 base::string16 title(ASCIIToUTF16("foo")); | |
| 294 GURL url("http://foo.com"); | |
| 295 const BookmarkNode* n1 = model->AddURL(model->other_node(), 0, title, url); | |
| 296 const BookmarkNode* n2 = model->AddURL(model->other_node(), 1, title, url); | |
| 297 | |
| 298 // Cut the nodes to the clipboard. | |
| 299 std::vector<const BookmarkNode*> nodes; | |
| 300 nodes.push_back(n1); | |
| 301 nodes.push_back(n2); | |
| 302 CopyToClipboard(model.get(), nodes, true); | |
| 303 | |
| 304 // Make sure the nodes were removed. | |
| 305 EXPECT_EQ(0, model->other_node()->child_count()); | |
| 306 | |
| 307 // Make sure observers were notified the set of changes should be grouped. | |
| 308 ExpectGroupedChangeCount(1, 1); | |
| 309 | |
| 310 // And make sure we can paste from the clipboard. | |
| 311 EXPECT_TRUE(CanPasteFromClipboard(model->other_node())); | |
| 312 } | |
| 313 #endif // !defined(OS_IOS) | |
| 314 | |
| 315 TEST_F(BookmarkUtilsTest, GetParentForNewNodes) { | |
| 316 test::TestBookmarkClient client; | |
| 317 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 318 // This tests the case where selection contains one item and that item is a | |
| 319 // folder. | |
| 320 std::vector<const BookmarkNode*> nodes; | |
| 321 nodes.push_back(model->bookmark_bar_node()); | |
| 322 int index = -1; | |
| 323 const BookmarkNode* real_parent = | |
| 324 GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
| 325 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
| 326 EXPECT_EQ(0, index); | |
| 327 | |
| 328 nodes.clear(); | |
| 329 | |
| 330 // This tests the case where selection contains one item and that item is an | |
| 331 // url. | |
| 332 const BookmarkNode* page1 = model->AddURL(model->bookmark_bar_node(), | |
| 333 0, | |
| 334 ASCIIToUTF16("Google"), | |
| 335 GURL("http://google.com")); | |
| 336 nodes.push_back(page1); | |
| 337 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
| 338 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
| 339 EXPECT_EQ(1, index); | |
| 340 | |
| 341 // This tests the case where selection has more than one item. | |
| 342 const BookmarkNode* folder1 = | |
| 343 model->AddFolder(model->bookmark_bar_node(), 1, ASCIIToUTF16("Folder 1")); | |
| 344 nodes.push_back(folder1); | |
| 345 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
| 346 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
| 347 EXPECT_EQ(2, index); | |
| 348 | |
| 349 // This tests the case where selection doesn't contain any items. | |
| 350 nodes.clear(); | |
| 351 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
| 352 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
| 353 EXPECT_EQ(2, index); | |
| 354 } | |
| 355 | |
| 356 // Verifies that meta info is copied when nodes are cloned. | |
| 357 TEST_F(BookmarkUtilsTest, CloneMetaInfo) { | |
| 358 test::TestBookmarkClient client; | |
| 359 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
| 360 // Add a node containing meta info. | |
| 361 const BookmarkNode* node = model->AddURL(model->other_node(), | |
| 362 0, | |
| 363 ASCIIToUTF16("foo bar"), | |
| 364 GURL("http://www.google.com")); | |
| 365 model->SetNodeMetaInfo(node, "somekey", "somevalue"); | |
| 366 model->SetNodeMetaInfo(node, "someotherkey", "someothervalue"); | |
| 367 | |
| 368 // Clone node to a different folder. | |
| 369 const BookmarkNode* folder = | |
| 370 model->AddFolder(model->bookmark_bar_node(), 0, ASCIIToUTF16("Folder")); | |
| 371 std::vector<BookmarkNodeData::Element> elements; | |
| 372 BookmarkNodeData::Element node_data(node); | |
| 373 elements.push_back(node_data); | |
| 374 EXPECT_EQ(0, folder->child_count()); | |
| 375 CloneBookmarkNode(model.get(), elements, folder, 0, false); | |
| 376 ASSERT_EQ(1, folder->child_count()); | |
| 377 | |
| 378 // Verify that the cloned node contains the same meta info. | |
| 379 const BookmarkNode* clone = folder->GetChild(0); | |
| 380 ASSERT_TRUE(clone->GetMetaInfoMap()); | |
| 381 EXPECT_EQ(2u, clone->GetMetaInfoMap()->size()); | |
| 382 std::string value; | |
| 383 EXPECT_TRUE(clone->GetMetaInfo("somekey", &value)); | |
| 384 EXPECT_EQ("somevalue", value); | |
| 385 EXPECT_TRUE(clone->GetMetaInfo("someotherkey", &value)); | |
| 386 EXPECT_EQ("someothervalue", value); | |
| 387 } | |
| 388 | |
| 389 } // namespace | |
| 390 } // namespace bookmark_utils | |
| OLD | NEW |