OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/bookmarks/browser/bookmark_model.h" | 5 #include "components/bookmarks/browser/bookmark_model.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/base_paths.h" | 10 #include "base/base_paths.h" |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
14 #include "base/containers/hash_tables.h" | 14 #include "base/containers/hash_tables.h" |
15 #include "base/strings/string16.h" | 15 #include "base/strings/string16.h" |
16 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
17 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
20 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 21 #include "components/bookmarks/browser/bookmark_match.h" |
21 #include "components/bookmarks/browser/bookmark_model_observer.h" | 22 #include "components/bookmarks/browser/bookmark_model_observer.h" |
22 #include "components/bookmarks/browser/bookmark_utils.h" | 23 #include "components/bookmarks/browser/bookmark_utils.h" |
23 #include "components/bookmarks/test/bookmark_test_helpers.h" | 24 #include "components/bookmarks/test/bookmark_test_helpers.h" |
24 #include "components/bookmarks/test/test_bookmark_client.h" | 25 #include "components/bookmarks/test/test_bookmark_client.h" |
| 26 #include "components/favicon_base/favicon_callback.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 28 #include "third_party/skia/include/core/SkBitmap.h" |
26 #include "ui/base/models/tree_node_iterator.h" | 29 #include "ui/base/models/tree_node_iterator.h" |
27 #include "ui/base/models/tree_node_model.h" | 30 #include "ui/base/models/tree_node_model.h" |
| 31 #include "ui/gfx/image/image.h" |
28 #include "url/gurl.h" | 32 #include "url/gurl.h" |
29 | 33 |
30 using base::ASCIIToUTF16; | 34 using base::ASCIIToUTF16; |
31 using base::Time; | 35 using base::Time; |
32 using base::TimeDelta; | 36 using base::TimeDelta; |
33 | 37 |
34 namespace bookmarks { | 38 namespace bookmarks { |
35 namespace { | 39 namespace { |
36 | 40 |
37 // Test cases used to test the removal of extra whitespace when adding | 41 // Test cases used to test the removal of extra whitespace when adding |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 } | 204 } |
201 } | 205 } |
202 | 206 |
203 void VerifyNoDuplicateIDs(BookmarkModel* model) { | 207 void VerifyNoDuplicateIDs(BookmarkModel* model) { |
204 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); | 208 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); |
205 base::hash_set<int64> ids; | 209 base::hash_set<int64> ids; |
206 while (it.has_next()) | 210 while (it.has_next()) |
207 ASSERT_TRUE(ids.insert(it.Next()->id()).second); | 211 ASSERT_TRUE(ids.insert(it.Next()->id()).second); |
208 } | 212 } |
209 | 213 |
| 214 } // namespace |
| 215 |
210 class BookmarkModelTest : public testing::Test, | 216 class BookmarkModelTest : public testing::Test, |
211 public BookmarkModelObserver { | 217 public BookmarkModelObserver { |
212 public: | 218 public: |
213 struct ObserverDetails { | 219 struct ObserverDetails { |
214 ObserverDetails() { | 220 ObserverDetails() { |
215 Set(NULL, NULL, -1, -1); | 221 Set(NULL, NULL, -1, -1); |
216 } | 222 } |
217 | 223 |
218 void Set(const BookmarkNode* node1, | 224 void Set(const BookmarkNode* node1, |
219 const BookmarkNode* node2, | 225 const BookmarkNode* node2, |
(...skipping 20 matching lines...) Expand all Loading... |
240 const BookmarkNode* node2_; | 246 const BookmarkNode* node2_; |
241 int index1_; | 247 int index1_; |
242 int index2_; | 248 int index2_; |
243 }; | 249 }; |
244 | 250 |
245 BookmarkModelTest() : model_(client_.CreateModel()) { | 251 BookmarkModelTest() : model_(client_.CreateModel()) { |
246 model_->AddObserver(this); | 252 model_->AddObserver(this); |
247 ClearCounts(); | 253 ClearCounts(); |
248 } | 254 } |
249 | 255 |
| 256 // Emulates the favicon getting asynchronously loaded. In production, the |
| 257 // favicon is asynchronously loaded when BookmarkModel::GetFavicon() is |
| 258 // called. |
| 259 void OnFaviconLoaded(BookmarkNode* node, const GURL& icon_url) { |
| 260 SkBitmap bitmap; |
| 261 bitmap.allocN32Pixels(16, 16); |
| 262 bitmap.eraseColor(SK_ColorBLUE); |
| 263 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); |
| 264 |
| 265 favicon_base::FaviconImageResult image_result; |
| 266 image_result.image = image; |
| 267 image_result.icon_url = icon_url; |
| 268 model_->OnFaviconDataAvailable(node, favicon_base::IconType::FAVICON, |
| 269 image_result); |
| 270 } |
| 271 |
250 void BookmarkModelLoaded(BookmarkModel* model, bool ids_reassigned) override { | 272 void BookmarkModelLoaded(BookmarkModel* model, bool ids_reassigned) override { |
251 // We never load from the db, so that this should never get invoked. | 273 // We never load from the db, so that this should never get invoked. |
252 NOTREACHED(); | 274 NOTREACHED(); |
253 } | 275 } |
254 | 276 |
255 void BookmarkNodeMoved(BookmarkModel* model, | 277 void BookmarkNodeMoved(BookmarkModel* model, |
256 const BookmarkNode* old_parent, | 278 const BookmarkNode* old_parent, |
257 int old_index, | 279 int old_index, |
258 const BookmarkNode* new_parent, | 280 const BookmarkNode* new_parent, |
259 int new_index) override { | 281 int new_index) override { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 ++reordered_count_; | 322 ++reordered_count_; |
301 } | 323 } |
302 | 324 |
303 void OnWillReorderBookmarkNode(BookmarkModel* model, | 325 void OnWillReorderBookmarkNode(BookmarkModel* model, |
304 const BookmarkNode* node) override { | 326 const BookmarkNode* node) override { |
305 ++before_reorder_count_; | 327 ++before_reorder_count_; |
306 } | 328 } |
307 | 329 |
308 void BookmarkNodeFaviconChanged(BookmarkModel* model, | 330 void BookmarkNodeFaviconChanged(BookmarkModel* model, |
309 const BookmarkNode* node) override { | 331 const BookmarkNode* node) override { |
310 // We never attempt to load favicons, so that this method never | |
311 // gets invoked. | |
312 } | 332 } |
313 | 333 |
314 void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) override { | 334 void ExtensiveBookmarkChangesBeginning(BookmarkModel* model) override { |
315 ++extensive_changes_beginning_count_; | 335 ++extensive_changes_beginning_count_; |
316 } | 336 } |
317 | 337 |
318 void ExtensiveBookmarkChangesEnded(BookmarkModel* model) override { | 338 void ExtensiveBookmarkChangesEnded(BookmarkModel* model) override { |
319 ++extensive_changes_ended_count_; | 339 ++extensive_changes_ended_count_; |
320 } | 340 } |
321 | 341 |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 const GURL url("http://foo.com"); | 618 const GURL url("http://foo.com"); |
599 model_->AddURL(folder, 0, title, url); | 619 model_->AddURL(folder, 0, title, url); |
600 | 620 |
601 ClearCounts(); | 621 ClearCounts(); |
602 | 622 |
603 // Now remove the folder. | 623 // Now remove the folder. |
604 model_->Remove(root->GetChild(0)); | 624 model_->Remove(root->GetChild(0)); |
605 ASSERT_EQ(0, root->child_count()); | 625 ASSERT_EQ(0, root->child_count()); |
606 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | 626 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); |
607 observer_details_.ExpectEquals(root, NULL, 0, -1); | 627 observer_details_.ExpectEquals(root, NULL, 0, -1); |
| 628 } |
608 | 629 |
609 // Make sure there is no mapping for the URL. | 630 // Test that removing a BookmarkNode from the BookmarkModel clears any data that |
610 ASSERT_TRUE(model_->GetMostRecentlyAddedUserNodeForURL(url) == NULL); | 631 // the BookmarkModel has cached about that BookmarkNode. |
| 632 TEST_F(BookmarkModelTest, RemoveURLClearsCachedData) { |
| 633 const BookmarkNode* root = model_->bookmark_bar_node(); |
| 634 base::string16 kTitle(ASCIIToUTF16("foo")); |
| 635 GURL kPageURL("http://www.google.com"); |
| 636 GURL kFaviconURL("http://www.google.com/favicon.ico"); |
| 637 |
| 638 const BookmarkNode* node = model_->AddURL(root, 0, kTitle, kPageURL); |
| 639 |
| 640 // Emulate the favicon getting asynchronously loaded. |
| 641 OnFaviconLoaded(AsMutable(node), kFaviconURL); |
| 642 |
| 643 // Test initial state. |
| 644 std::vector<const BookmarkNode*> nodes; |
| 645 model_->GetNodesByURL(kPageURL, &nodes); |
| 646 ASSERT_EQ(1u, nodes.size()); |
| 647 ASSERT_EQ(node, nodes[0]); |
| 648 |
| 649 nodes.clear(); |
| 650 model_->GetNodesByIconURL(kFaviconURL, &nodes); |
| 651 ASSERT_EQ(1u, nodes.size()); |
| 652 ASSERT_EQ(node, nodes[0]); |
| 653 |
| 654 std::vector<BookmarkMatch> matches; |
| 655 model_->GetBookmarksMatching(kTitle, 1u, &matches); |
| 656 ASSERT_EQ(1u, nodes.size()); |
| 657 ASSERT_EQ(node, nodes[0]); |
| 658 |
| 659 // Remove |node| from the BookmarkModel. |
| 660 model_->Remove(nodes[0]); |
| 661 |
| 662 // Test that the BookmarkModel has forgotten about |node|. |
| 663 nodes.clear(); |
| 664 model_->GetNodesByURL(kPageURL, &nodes); |
| 665 EXPECT_TRUE(nodes.empty()); |
| 666 |
| 667 model_->GetNodesByIconURL(kFaviconURL, &nodes); |
| 668 EXPECT_TRUE(nodes.empty()); |
| 669 |
| 670 matches.clear(); |
| 671 model_->GetBookmarksMatching(kTitle, 1u, &matches); |
| 672 EXPECT_TRUE(matches.empty()); |
611 } | 673 } |
612 | 674 |
613 TEST_F(BookmarkModelTest, RemoveAllUserBookmarks) { | 675 TEST_F(BookmarkModelTest, RemoveAllUserBookmarks) { |
614 const BookmarkNode* bookmark_bar_node = model_->bookmark_bar_node(); | 676 const BookmarkNode* bookmark_bar_node = model_->bookmark_bar_node(); |
615 | 677 |
616 ClearCounts(); | 678 ClearCounts(); |
617 | 679 |
618 // Add a url to bookmark bar. | 680 // Add a url to bookmark bar. |
619 base::string16 title(ASCIIToUTF16("foo")); | 681 base::string16 title(ASCIIToUTF16("foo")); |
620 GURL url("http://foo.com"); | 682 GURL url("http://foo.com"); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 | 736 |
675 ClearCounts(); | 737 ClearCounts(); |
676 | 738 |
677 url = GURL("http://foo2.com"); | 739 url = GURL("http://foo2.com"); |
678 model_->SetURL(node, url); | 740 model_->SetURL(node, url); |
679 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); | 741 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); |
680 observer_details_.ExpectEquals(node, NULL, -1, -1); | 742 observer_details_.ExpectEquals(node, NULL, -1, -1); |
681 EXPECT_EQ(url, node->url()); | 743 EXPECT_EQ(url, node->url()); |
682 } | 744 } |
683 | 745 |
| 746 // Test that changing a BookmarkNode's page URL clears the BookmarkModel's |
| 747 // cached favicon data and the BookmarkNode's favicon data. |
| 748 TEST_F(BookmarkModelTest, SetURLClearsFaviconData) { |
| 749 const BookmarkNode* root = model_->bookmark_bar_node(); |
| 750 base::string16 kTitle(ASCIIToUTF16("foo")); |
| 751 GURL kPageURL1("http://www.google.com"); |
| 752 GURL kFaviconURL1("http://www.google.com/favicon.ico"); |
| 753 GURL kPageURL2("http://www.wikipedia.org"); |
| 754 |
| 755 const BookmarkNode* node = model_->AddURL(root, 0, kTitle, kPageURL1); |
| 756 |
| 757 // Emulate the favicon getting asynchronously loaded. |
| 758 OnFaviconLoaded(AsMutable(node), kFaviconURL1); |
| 759 |
| 760 // Test initial state. |
| 761 std::vector<const BookmarkNode*> nodes; |
| 762 model_->GetNodesByIconURL(kFaviconURL1, &nodes); |
| 763 ASSERT_EQ(1u, nodes.size()); |
| 764 ASSERT_EQ(node, nodes[0]); |
| 765 ASSERT_EQ(kFaviconURL1, node->icon_url()); |
| 766 |
| 767 // Change |node|'s page URL |
| 768 model_->SetURL(node, kPageURL2); |
| 769 |
| 770 // BookmarkModel should have forgotten about |kFaviconURL1|. |
| 771 nodes.clear(); |
| 772 model_->GetNodesByIconURL(kFaviconURL1, &nodes); |
| 773 EXPECT_TRUE(nodes.empty()); |
| 774 |
| 775 // |node|'s favicon data should have been cleared. |
| 776 EXPECT_EQ(GURL(), node->icon_url()); |
| 777 } |
| 778 |
684 TEST_F(BookmarkModelTest, SetDateAdded) { | 779 TEST_F(BookmarkModelTest, SetDateAdded) { |
685 const BookmarkNode* root = model_->bookmark_bar_node(); | 780 const BookmarkNode* root = model_->bookmark_bar_node(); |
686 const base::string16 title(ASCIIToUTF16("foo")); | 781 const base::string16 title(ASCIIToUTF16("foo")); |
687 GURL url("http://foo.com"); | 782 GURL url("http://foo.com"); |
688 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | 783 const BookmarkNode* node = model_->AddURL(root, 0, title, url); |
689 | 784 |
690 ClearCounts(); | 785 ClearCounts(); |
691 | 786 |
692 base::Time new_time = base::Time::Now() + base::TimeDelta::FromMinutes(20); | 787 base::Time new_time = base::Time::Now() + base::TimeDelta::FromMinutes(20); |
693 model_->SetDateAdded(node, new_time); | 788 model_->SetDateAdded(node, new_time); |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 PopulateNodeFromString(data[i].mobile_contents, &mobile); | 1269 PopulateNodeFromString(data[i].mobile_contents, &mobile); |
1175 PopulateBookmarkNode(&mobile, model.get(), model->mobile_node()); | 1270 PopulateBookmarkNode(&mobile, model.get(), model->mobile_node()); |
1176 | 1271 |
1177 VerifyModelMatchesNode(&bbn, model->bookmark_bar_node()); | 1272 VerifyModelMatchesNode(&bbn, model->bookmark_bar_node()); |
1178 VerifyModelMatchesNode(&other, model->other_node()); | 1273 VerifyModelMatchesNode(&other, model->other_node()); |
1179 VerifyModelMatchesNode(&mobile, model->mobile_node()); | 1274 VerifyModelMatchesNode(&mobile, model->mobile_node()); |
1180 VerifyNoDuplicateIDs(model.get()); | 1275 VerifyNoDuplicateIDs(model.get()); |
1181 } | 1276 } |
1182 } | 1277 } |
1183 | 1278 |
1184 } // namespace | |
1185 } // namespace bookmarks | 1279 } // namespace bookmarks |
OLD | NEW |