Index: chrome/test/live_sync/bookmarks_helper.cc |
diff --git a/chrome/test/live_sync/bookmarks_helper.cc b/chrome/test/live_sync/bookmarks_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e50d3ad0b771006c5668cb29c3f6261a8b3aa788 |
--- /dev/null |
+++ b/chrome/test/live_sync/bookmarks_helper.cc |
@@ -0,0 +1,633 @@ |
+// Copyright (c) 2011 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 "chrome/test/live_sync/bookmarks_helper.h" |
+ |
+#include "base/rand_util.h" |
+#include "base/string_number_conversions.h" |
+#include "base/stringprintf.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/bookmarks/bookmark_model.h" |
+#include "chrome/browser/bookmarks/bookmark_model_observer.h" |
+#include "chrome/browser/bookmarks/bookmark_utils.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/sync/glue/bookmark_change_processor.h" |
+#include "chrome/browser/sync/profile_sync_service_harness.h" |
+#include "chrome/test/live_sync/live_sync_test.h" |
+#include "chrome/test/ui_test_utils.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "ui/base/models/tree_node_iterator.h" |
+#include "ui/gfx/codec/png_codec.h" |
+ |
+namespace { |
+ |
+// Helper class used to wait for changes to take effect on the favicon of a |
+// particular bookmark node in a particular bookmark model. |
+class FaviconChangeObserver : public BookmarkModelObserver { |
+ public: |
+ FaviconChangeObserver(BookmarkModel* model, const BookmarkNode* node) |
+ : model_(model), |
+ node_(node), |
+ wait_for_load_(false) { |
+ model->AddObserver(this); |
+ } |
+ virtual ~FaviconChangeObserver() { |
+ model_->RemoveObserver(this); |
+ } |
+ void WaitForGetFavicon() { |
+ wait_for_load_ = true; |
+ ui_test_utils::RunMessageLoop(); |
+ ASSERT_TRUE(node_->is_favicon_loaded()); |
+ } |
+ void WaitForSetFavicon() { |
+ wait_for_load_ = false; |
+ ui_test_utils::RunMessageLoop(); |
+ } |
+ virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE {} |
+ virtual void BookmarkNodeMoved(BookmarkModel* model, |
+ const BookmarkNode* old_parent, |
+ int old_index, |
+ const BookmarkNode* new_parent, |
+ int new_index) OVERRIDE {} |
+ virtual void BookmarkNodeAdded(BookmarkModel* model, |
+ const BookmarkNode* parent, |
+ int index) OVERRIDE {} |
+ virtual void BookmarkNodeRemoved(BookmarkModel* model, |
+ const BookmarkNode* parent, |
+ int old_index, |
+ const BookmarkNode* node) OVERRIDE {} |
+ virtual void BookmarkNodeChanged(BookmarkModel* model, |
+ const BookmarkNode* node) OVERRIDE { |
+ if (model == model_ && node == node_) |
+ model->GetFavicon(node); |
+ } |
+ virtual void BookmarkNodeChildrenReordered( |
+ BookmarkModel* model, |
+ const BookmarkNode* node) OVERRIDE {} |
+ virtual void BookmarkNodeFaviconChanged( |
+ BookmarkModel* model, |
+ const BookmarkNode* node) OVERRIDE { |
+ if (model == model_ && node == node_) { |
+ if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded())) |
+ MessageLoopForUI::current()->Quit(); |
+ } |
+ } |
+ |
+ private: |
+ BookmarkModel* model_; |
+ const BookmarkNode* node_; |
+ bool wait_for_load_; |
+ DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver); |
+}; |
+ |
+} // namespace |
+ |
+BookmarksHelper::BookmarksHelper() {} |
+ |
+BookmarksHelper::~BookmarksHelper() {} |
+ |
+// static |
+BookmarkModel* BookmarksHelper::GetBookmarkModel(int index) { |
+ return test()->GetProfile(index)->GetBookmarkModel(); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::GetBookmarkBarNode(int index) { |
+ return GetBookmarkModel(index)->bookmark_bar_node(); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::GetOtherNode(int index) { |
+ return GetBookmarkModel(index)->other_node(); |
+} |
+ |
+// static |
+BookmarkModel* BookmarksHelper::GetVerifierBookmarkModel() { |
+ return test()->verifier()->GetBookmarkModel(); |
+} |
+ |
+// static |
+bool BookmarksHelper::EnableEncryption(int index) { |
+ return test()->GetClient(index)->EnableEncryptionForType(syncable::BOOKMARKS); |
+} |
+ |
+// static |
+bool BookmarksHelper::IsEncrypted(int index) { |
+ return test()->GetClient(index)->IsTypeEncrypted(syncable::BOOKMARKS); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddURL(int profile, |
+ const std::wstring& title, |
+ const GURL& url) { |
+ return AddURL(profile, GetBookmarkBarNode(profile), 0, title, url); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddURL(int profile, |
+ int index, |
+ const std::wstring& title, |
+ const GURL& url) { |
+ return AddURL(profile, GetBookmarkBarNode(profile), index, title, url); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddURL(int profile, |
+ const BookmarkNode* parent, |
+ int index, |
+ const std::wstring& title, |
+ const GURL& url) { |
+ if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) { |
+ LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ return NULL; |
+ } |
+ const BookmarkNode* result = GetBookmarkModel(profile)-> |
+ AddURL(parent, index, WideToUTF16(title), url); |
+ if (!result) { |
+ LOG(ERROR) << "Could not add bookmark " << title << " to Profile " |
+ << profile; |
+ return NULL; |
+ } |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_parent = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); |
+ const BookmarkNode* v_node = GetVerifierBookmarkModel()-> |
+ AddURL(v_parent, index, WideToUTF16(title), url); |
+ if (!v_node) { |
+ LOG(ERROR) << "Could not add bookmark " << title << " to the verifier"; |
+ return NULL; |
+ } |
+ EXPECT_TRUE(NodesMatch(v_node, result)); |
+ } |
+ return result; |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddFolder(int profile, |
+ const std::wstring& title) { |
+ return AddFolder(profile, GetBookmarkBarNode(profile), 0, title); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddFolder(int profile, |
+ int index, |
+ const std::wstring& title) { |
+ return AddFolder(profile, GetBookmarkBarNode(profile), index, title); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::AddFolder(int profile, |
+ const BookmarkNode* parent, |
+ int index, |
+ const std::wstring& title) { |
+ if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) { |
+ LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ return NULL; |
+ } |
+ const BookmarkNode* result = |
+ GetBookmarkModel(profile)->AddFolder(parent, index, WideToUTF16(title)); |
+ EXPECT_TRUE(result); |
+ if (!result) { |
+ LOG(ERROR) << "Could not add folder " << title << " to Profile " |
+ << profile; |
+ return NULL; |
+ } |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_parent = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); |
+ const BookmarkNode* v_node = GetVerifierBookmarkModel()->AddFolder( |
+ v_parent, index, WideToUTF16(title)); |
+ if (!v_node) { |
+ LOG(ERROR) << "Could not add folder " << title << " to the verifier"; |
+ return NULL; |
+ } |
+ EXPECT_TRUE(NodesMatch(v_node, result)); |
+ } |
+ return result; |
+} |
+ |
+// static |
+void BookmarksHelper::SetTitle(int profile, |
+ const BookmarkNode* node, |
+ const std::wstring& new_title) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) |
+ << "Node " << node->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_node = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
+ GetVerifierBookmarkModel()->SetTitle(v_node, WideToUTF16(new_title)); |
+ } |
+ GetBookmarkModel(profile)->SetTitle(node, WideToUTF16(new_title)); |
+} |
+ |
+// static |
+void BookmarksHelper::SetFavicon( |
+ int profile, |
+ const BookmarkNode* node, |
+ const std::vector<unsigned char>& icon_bytes_vector) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) |
+ << "Node " << node->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ ASSERT_EQ(BookmarkNode::URL, node->type()) |
+ << "Node " << node->GetTitle() << " must be a url."; |
+ if (urls_with_favicons_ == NULL) |
+ urls_with_favicons_ = new std::set<GURL>(); |
+ urls_with_favicons_->insert(node->url()); |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_node = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
+ FaviconChangeObserver v_observer(GetVerifierBookmarkModel(), v_node); |
+ browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon( |
+ v_node, test()->verifier(), icon_bytes_vector); |
+ v_observer.WaitForSetFavicon(); |
+ } |
+ FaviconChangeObserver observer(GetBookmarkModel(profile), node); |
+ browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon( |
+ node, test()->GetProfile(profile), icon_bytes_vector); |
+ observer.WaitForSetFavicon(); |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::SetURL(int profile, |
+ const BookmarkNode* node, |
+ const GURL& new_url) { |
+ if (GetBookmarkModel(profile)->GetNodeByID(node->id()) != node) { |
+ LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ return NULL; |
+ } |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_node = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
+ bookmark_utils::ApplyEditsWithNoFolderChange( |
+ GetVerifierBookmarkModel(), |
+ v_node->parent(), |
+ BookmarkEditor::EditDetails(v_node), |
+ v_node->GetTitle(), |
+ new_url); |
+ } |
+ return bookmark_utils::ApplyEditsWithNoFolderChange( |
+ GetBookmarkModel(profile), |
+ node->parent(), |
+ BookmarkEditor::EditDetails(node), |
+ node->GetTitle(), |
+ new_url); |
+} |
+ |
+// static |
+void BookmarksHelper::Move(int profile, |
+ const BookmarkNode* node, |
+ const BookmarkNode* new_parent, |
+ int index) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node) |
+ << "Node " << node->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_new_parent = NULL; |
+ const BookmarkNode* v_node = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), new_parent, &v_new_parent); |
+ FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node); |
+ GetVerifierBookmarkModel()->Move(v_node, v_new_parent, index); |
+ } |
+ GetBookmarkModel(profile)->Move(node, new_parent, index); |
+} |
+ |
+// static |
+void BookmarksHelper::Remove(int profile, |
+ const BookmarkNode* parent, |
+ int index) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) |
+ << "Node " << parent->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ if (test()->use_verifier()) { |
tim (not reviewing)
2011/07/28 05:22:41
Almost (almost) seems like a job for inheritance+f
Raghu Simha
2011/07/28 09:36:54
I implemented this via a dynamic check because a t
|
+ const BookmarkNode* v_parent = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); |
+ ASSERT_TRUE(NodesMatch(parent->GetChild(index), v_parent->GetChild(index))); |
+ GetVerifierBookmarkModel()->Remove(v_parent, index); |
+ } |
+ GetBookmarkModel(profile)->Remove(parent, index); |
+} |
+ |
+// static |
+void BookmarksHelper::SortChildren(int profile, |
+ const BookmarkNode* parent) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) |
+ << "Node " << parent->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ if (test()->use_verifier()) { |
+ const BookmarkNode* v_parent = NULL; |
+ FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent); |
+ GetVerifierBookmarkModel()->SortChildren(v_parent); |
+ } |
+ GetBookmarkModel(profile)->SortChildren(parent); |
+} |
+ |
+// static |
+void BookmarksHelper::ReverseChildOrder(int profile, |
+ const BookmarkNode* parent) { |
+ ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent) |
+ << "Node " << parent->GetTitle() << " does not belong to " |
+ << "Profile " << profile; |
+ int child_count = parent->child_count(); |
+ if (child_count <= 0) |
+ return; |
+ for (int index = 0; index < child_count; ++index) { |
+ Move(profile, parent->GetChild(index), parent, child_count - index); |
+ } |
+} |
+ |
+// static |
+bool BookmarksHelper::ModelMatchesVerifier(int profile) { |
+ if (!test()->use_verifier()) { |
+ LOG(ERROR) << "Illegal to call ModelMatchesVerifier() after " |
+ << "DisableVerifier(). Use ModelsMatch() instead."; |
+ return false; |
+ } |
+ return BookmarkModelsMatch(GetVerifierBookmarkModel(), |
+ GetBookmarkModel(profile)); |
+} |
+ |
+// static |
+bool BookmarksHelper::AllModelsMatchVerifier() { |
+ for (int i = 0; i < test()->num_clients(); ++i) { |
+ if (!ModelMatchesVerifier(i)) { |
+ LOG(ERROR) << "Model " << i << " does not match the verifier."; |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+// static |
+bool BookmarksHelper::ModelsMatch(int profile_a, int profile_b) { |
+ return BookmarkModelsMatch(GetBookmarkModel(profile_a), |
+ GetBookmarkModel(profile_b)); |
+} |
+ |
+// static |
+bool BookmarksHelper::AllModelsMatch() { |
+ for (int i = 1; i < test()->num_clients(); ++i) { |
+ if (!ModelsMatch(0, i)) { |
+ LOG(ERROR) << "Model " << i << " does not match Model 0."; |
+ return false; |
+ } |
+ } |
+ return true; |
+} |
+ |
+// static |
+bool BookmarksHelper::ContainsDuplicateBookmarks(int profile) { |
+ ui::TreeNodeIterator<const BookmarkNode> iterator( |
+ GetBookmarkModel(profile)->root_node()); |
+ while (iterator.has_next()) { |
+ const BookmarkNode* node = iterator.Next(); |
+ if (node->is_folder()) |
+ continue; |
+ std::vector<const BookmarkNode*> nodes; |
+ GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes); |
+ EXPECT_TRUE(nodes.size() >= 1); |
+ for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin(); |
+ it != nodes.end(); ++it) { |
+ if (node->id() != (*it)->id() && |
+ node->parent() == (*it)->parent() && |
+ node->GetTitle() == (*it)->GetTitle()){ |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+} |
+ |
+// static |
+const BookmarkNode* BookmarksHelper::GetUniqueNodeByURL(int profile, |
+ const GURL& url) { |
+ std::vector<const BookmarkNode*> nodes; |
+ GetBookmarkModel(profile)->GetNodesByURL(url, &nodes); |
+ EXPECT_EQ(1U, nodes.size()); |
+ if (nodes.empty()) |
+ return NULL; |
+ return nodes[0]; |
+} |
+ |
+// static |
+int BookmarksHelper::CountBookmarksWithTitlesMatching( |
+ int profile, |
+ const std::wstring& title) { |
+ return CountNodesWithTitlesMatching(GetBookmarkModel(profile), |
+ BookmarkNode::URL, |
+ WideToUTF16(title)); |
+} |
+ |
+// static |
+int BookmarksHelper::CountFoldersWithTitlesMatching( |
+ int profile, |
+ const std::wstring& title) { |
+ return CountNodesWithTitlesMatching(GetBookmarkModel(profile), |
+ BookmarkNode::FOLDER, |
+ WideToUTF16(title)); |
+} |
+ |
+// static |
+int BookmarksHelper::CountNodesWithTitlesMatching( |
+ BookmarkModel* model, |
+ BookmarkNode::Type node_type, |
+ const string16& title) { |
+ ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node()); |
+ // Walk through the model tree looking for bookmark nodes of node type |
+ // |node_type| whose titles match |title|. |
+ int count = 0; |
+ while (iterator.has_next()) { |
+ const BookmarkNode* node = iterator.Next(); |
+ if ((node->type() == node_type) && (node->GetTitle() == title)) |
+ ++count; |
+ } |
+ return count; |
+} |
+ |
+// static |
+std::vector<unsigned char> BookmarksHelper::CreateFavicon(int seed) { |
+ const int w = 16; |
+ const int h = 16; |
+ SkBitmap bmp; |
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, w, h); |
+ bmp.allocPixels(); |
+ uint32_t* src_data = bmp.getAddr32(0, 0); |
+ for (int i = 0; i < w * h; ++i) { |
+ src_data[i] = SkPreMultiplyARGB((seed + i) % 255, |
+ (seed + i) % 250, |
+ (seed + i) % 245, |
+ (seed + i) % 240); |
+ } |
+ std::vector<unsigned char> favicon; |
+ gfx::PNGCodec::EncodeBGRASkBitmap(bmp, false, &favicon); |
+ return favicon; |
+} |
+ |
+// static |
+std::string BookmarksHelper::IndexedURL(int i) { |
+ return StringPrintf("http://www.host.ext:1234/path/filename/%d", i); |
+} |
+ |
+// static |
+std::wstring BookmarksHelper::IndexedURLTitle(int i) { |
+ return StringPrintf(L"URL Title %d", i); |
+} |
+ |
+// static |
+std::wstring BookmarksHelper::IndexedFolderName(int i) { |
+ return StringPrintf(L"Folder Name %d", i); |
+} |
+ |
+// static |
+std::wstring BookmarksHelper::IndexedSubfolderName(int i) { |
+ return StringPrintf(L"Subfolder Name %d", i); |
+} |
+ |
+// static |
+std::wstring BookmarksHelper::IndexedSubsubfolderName(int i) { |
+ return StringPrintf(L"Subsubfolder Name %d", i); |
+} |
+ |
+// static |
+void BookmarksHelper::FindNodeInVerifier(BookmarkModel* foreign_model, |
+ const BookmarkNode* foreign_node, |
+ const BookmarkNode** result) { |
+ // Climb the tree. |
+ std::stack<int> path; |
+ const BookmarkNode* walker = foreign_node; |
+ while (walker != foreign_model->root_node()) { |
+ path.push(walker->parent()->GetIndexOf(walker)); |
+ walker = walker->parent(); |
+ } |
+ |
+ // Swing over to the other tree. |
+ walker = GetVerifierBookmarkModel()->root_node(); |
+ |
+ // Climb down. |
+ while (!path.empty()) { |
+ ASSERT_TRUE(walker->is_folder()); |
+ ASSERT_LT(path.top(), walker->child_count()); |
+ walker = walker->GetChild(path.top()); |
+ path.pop(); |
+ } |
+ |
+ ASSERT_TRUE(NodesMatch(foreign_node, walker)); |
+ *result = walker; |
+} |
+ |
+// static |
+bool BookmarksHelper::BookmarkModelsMatch(BookmarkModel* model_a, |
+ BookmarkModel* model_b) { |
+ bool ret_val = true; |
+ ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node()); |
+ ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node()); |
+ while (iterator_a.has_next()) { |
+ const BookmarkNode* node_a = iterator_a.Next(); |
+ if (!iterator_b.has_next()) { |
+ LOG(ERROR) << "Models do not match."; |
+ return false; |
+ } |
+ const BookmarkNode* node_b = iterator_b.Next(); |
+ ret_val = ret_val && NodesMatch(node_a, node_b); |
+ if (node_a->is_folder() || node_b->is_folder()) |
+ continue; |
+ ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b); |
+ } |
+ ret_val = ret_val && (!iterator_b.has_next()); |
+ return ret_val; |
+} |
+ |
+// static |
+bool BookmarksHelper::NodesMatch(const BookmarkNode* node_a, |
+ const BookmarkNode* node_b) { |
+ if (node_a == NULL || node_b == NULL) |
+ return node_a == node_b; |
+ if (node_a->is_folder() != node_b->is_folder()) { |
+ LOG(ERROR) << "Cannot compare folder with bookmark"; |
+ return false; |
+ } |
+ if (node_a->GetTitle() != node_b->GetTitle()) { |
+ LOG(ERROR) << "Title mismatch: " << node_a->GetTitle() << " vs. " |
+ << node_b->GetTitle(); |
+ return false; |
+ } |
+ if (node_a->url() != node_b->url()) { |
+ LOG(ERROR) << "URL mismatch: " << node_a->url() << " vs. " |
+ << node_b->url(); |
+ return false; |
+ } |
+ if (node_a->parent()->GetIndexOf(node_a) != |
+ node_b->parent()->GetIndexOf(node_b)) { |
+ LOG(ERROR) << "Index mismatch: " |
+ << node_a->parent()->GetIndexOf(node_a) << " vs. " |
+ << node_b->parent()->GetIndexOf(node_b); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+// static |
+bool BookmarksHelper::FaviconsMatch(BookmarkModel* model_a, |
+ BookmarkModel* model_b, |
+ const BookmarkNode* node_a, |
+ const BookmarkNode* node_b) { |
+ const SkBitmap& bitmap_a = GetFavicon(model_a, node_a); |
+ const SkBitmap& bitmap_b = GetFavicon(model_b, node_b); |
+ return FaviconBitmapsMatch(bitmap_a, bitmap_b); |
+} |
+ |
+// static |
+const SkBitmap& BookmarksHelper::GetFavicon(BookmarkModel* model, |
+ const BookmarkNode* node) { |
+ // If a favicon wasn't explicitly set for a particular URL, simply return its |
+ // blank favicon. |
+ if (!urls_with_favicons_ || |
+ urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) { |
+ return node->favicon(); |
+ } |
+ // If a favicon was explicitly set, we may need to wait for it to be loaded |
+ // via BookmarkModel::GetFavIcon(), which is an asynchronous operation. |
+ if (!node->is_favicon_loaded()) { |
+ FaviconChangeObserver observer(model, node); |
+ model->GetFavicon(node); |
+ observer.WaitForGetFavicon(); |
+ } |
+ EXPECT_TRUE(node->is_favicon_loaded()); |
+ return node->favicon(); |
+} |
+ |
+// static |
+bool BookmarksHelper::FaviconBitmapsMatch(const SkBitmap& bitmap_a, |
+ const SkBitmap& bitmap_b) { |
+ if (bitmap_a.getSize() == 0U && bitmap_a.getSize() == 0U) |
+ return true; |
+ if ((bitmap_a.getSize() != bitmap_b.getSize()) || |
+ (bitmap_a.width() != bitmap_b.width()) || |
+ (bitmap_a.height() != bitmap_b.height())) { |
+ LOG(ERROR) << "Favicon size mismatch: " << bitmap_a.getSize() << " (" |
+ << bitmap_a.width() << "x" << bitmap_a.height() << ") vs. " |
+ << bitmap_b.getSize() << " (" << bitmap_b.width() << "x" |
+ << bitmap_b.height() << ")"; |
+ return false; |
+ } |
+ SkAutoLockPixels bitmap_lock_a(bitmap_a); |
+ SkAutoLockPixels bitmap_lock_b(bitmap_b); |
+ void* node_pixel_addr_a = bitmap_a.getPixels(); |
+ EXPECT_TRUE(node_pixel_addr_a); |
+ void* node_pixel_addr_b = bitmap_b.getPixels(); |
+ EXPECT_TRUE(node_pixel_addr_b); |
+ if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) { |
+ LOG(ERROR) << "Favicon bitmap mismatch"; |
+ return false; |
+ } else { |
+ return true; |
+ } |
+} |
+ |
+// static |
+std::set<GURL>* BookmarksHelper::urls_with_favicons_ = NULL; |