Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / bookmarks_helper.cc
blob06baa996da5addd17053a557d05ba50ea18664eb
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.
5 #include "chrome/browser/sync/test/integration/bookmarks_helper.h"
7 #include "base/compiler_specific.h"
8 #include "base/file_util.h"
9 #include "base/path_service.h"
10 #include "base/rand_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "chrome/browser/bookmarks/bookmark_model.h"
17 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
18 #include "chrome/browser/bookmarks/bookmark_model_observer.h"
19 #include "chrome/browser/favicon/favicon_service_factory.h"
20 #include "chrome/browser/favicon/favicon_util.h"
21 #include "chrome/browser/history/history_db_task.h"
22 #include "chrome/browser/history/history_service_factory.h"
23 #include "chrome/browser/history/history_types.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/sync/glue/bookmark_change_processor.h"
26 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
27 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
28 #include "chrome/browser/sync/test/integration/sync_test.h"
29 #include "chrome/common/chrome_paths.h"
30 #include "chrome/test/base/ui_test_utils.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/skia/include/core/SkBitmap.h"
33 #include "ui/base/models/tree_node_iterator.h"
34 #include "ui/gfx/image/image_skia.h"
36 using sync_datatype_helper::test;
38 namespace {
40 // History task which runs all pending tasks on the history thread and
41 // signals when the tasks have completed.
42 class HistoryEmptyTask : public history::HistoryDBTask {
43 public:
44 explicit HistoryEmptyTask(base::WaitableEvent* done) : done_(done) {}
46 virtual bool RunOnDBThread(history::HistoryBackend* backend,
47 history::HistoryDatabase* db) OVERRIDE {
48 content::RunAllPendingInMessageLoop();
49 done_->Signal();
50 return true;
53 virtual void DoneRunOnMainThread() OVERRIDE {}
55 private:
56 virtual ~HistoryEmptyTask() {}
58 base::WaitableEvent* done_;
61 // Helper class used to wait for changes to take effect on the favicon of a
62 // particular bookmark node in a particular bookmark model.
63 class FaviconChangeObserver : public BookmarkModelObserver {
64 public:
65 FaviconChangeObserver(BookmarkModel* model, const BookmarkNode* node)
66 : model_(model),
67 node_(node),
68 wait_for_load_(false) {
69 model->AddObserver(this);
71 virtual ~FaviconChangeObserver() {
72 model_->RemoveObserver(this);
74 void WaitForGetFavicon() {
75 wait_for_load_ = true;
76 content::RunMessageLoop();
77 ASSERT_TRUE(node_->is_favicon_loaded());
78 ASSERT_FALSE(model_->GetFavicon(node_).IsEmpty());
80 void WaitForSetFavicon() {
81 wait_for_load_ = false;
82 content::RunMessageLoop();
84 virtual void BookmarkModelLoaded(BookmarkModel* model,
85 bool ids_reassigned) OVERRIDE {}
86 virtual void BookmarkNodeMoved(BookmarkModel* model,
87 const BookmarkNode* old_parent,
88 int old_index,
89 const BookmarkNode* new_parent,
90 int new_index) OVERRIDE {}
91 virtual void BookmarkNodeAdded(BookmarkModel* model,
92 const BookmarkNode* parent,
93 int index) OVERRIDE {}
94 virtual void BookmarkNodeRemoved(BookmarkModel* model,
95 const BookmarkNode* parent,
96 int old_index,
97 const BookmarkNode* node) OVERRIDE {}
98 virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE {}
100 virtual void BookmarkNodeChanged(BookmarkModel* model,
101 const BookmarkNode* node) OVERRIDE {
102 if (model == model_ && node == node_)
103 model->GetFavicon(node);
105 virtual void BookmarkNodeChildrenReordered(
106 BookmarkModel* model,
107 const BookmarkNode* node) OVERRIDE {}
108 virtual void BookmarkNodeFaviconChanged(
109 BookmarkModel* model,
110 const BookmarkNode* node) OVERRIDE {
111 if (model == model_ && node == node_) {
112 if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded()))
113 base::MessageLoopForUI::current()->Quit();
117 private:
118 BookmarkModel* model_;
119 const BookmarkNode* node_;
120 bool wait_for_load_;
121 DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver);
124 // A collection of URLs for which we have added favicons. Since loading a
125 // favicon is an asynchronous operation and doesn't necessarily invoke a
126 // callback, this collection is used to determine if we must wait for a URL's
127 // favicon to load or not.
128 std::set<GURL>* urls_with_favicons_ = NULL;
130 // Returns the number of nodes of node type |node_type| in |model| whose
131 // titles match the string |title|.
132 int CountNodesWithTitlesMatching(BookmarkModel* model,
133 BookmarkNode::Type node_type,
134 const base::string16& title) {
135 ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node());
136 // Walk through the model tree looking for bookmark nodes of node type
137 // |node_type| whose titles match |title|.
138 int count = 0;
139 while (iterator.has_next()) {
140 const BookmarkNode* node = iterator.Next();
141 if ((node->type() == node_type) && (node->GetTitle() == title))
142 ++count;
144 return count;
147 // Checks if the favicon data in |bitmap_a| and |bitmap_b| are equivalent.
148 // Returns true if they match.
149 bool FaviconBitmapsMatch(const SkBitmap& bitmap_a, const SkBitmap& bitmap_b) {
150 if (bitmap_a.getSize() == 0U && bitmap_b.getSize() == 0U)
151 return true;
152 if ((bitmap_a.getSize() != bitmap_b.getSize()) ||
153 (bitmap_a.width() != bitmap_b.width()) ||
154 (bitmap_a.height() != bitmap_b.height())) {
155 LOG(ERROR) << "Favicon size mismatch: " << bitmap_a.getSize() << " ("
156 << bitmap_a.width() << "x" << bitmap_a.height() << ") vs. "
157 << bitmap_b.getSize() << " (" << bitmap_b.width() << "x"
158 << bitmap_b.height() << ")";
159 return false;
161 SkAutoLockPixels bitmap_lock_a(bitmap_a);
162 SkAutoLockPixels bitmap_lock_b(bitmap_b);
163 void* node_pixel_addr_a = bitmap_a.getPixels();
164 EXPECT_TRUE(node_pixel_addr_a);
165 void* node_pixel_addr_b = bitmap_b.getPixels();
166 EXPECT_TRUE(node_pixel_addr_b);
167 if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) {
168 LOG(ERROR) << "Favicon bitmap mismatch";
169 return false;
170 } else {
171 return true;
175 // Represents a favicon image and the icon URL associated with it.
176 struct FaviconData {
177 FaviconData() {
180 FaviconData(const gfx::Image& favicon_image,
181 const GURL& favicon_url)
182 : image(favicon_image),
183 icon_url(favicon_url) {
186 ~FaviconData() {
189 gfx::Image image;
190 GURL icon_url;
193 // Gets the favicon and icon URL associated with |node| in |model|.
194 FaviconData GetFaviconData(BookmarkModel* model,
195 const BookmarkNode* node) {
196 // If a favicon wasn't explicitly set for a particular URL, simply return its
197 // blank favicon.
198 if (!urls_with_favicons_ ||
199 urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) {
200 return FaviconData();
202 // If a favicon was explicitly set, we may need to wait for it to be loaded
203 // via BookmarkModel::GetFavicon(), which is an asynchronous operation.
204 if (!node->is_favicon_loaded()) {
205 FaviconChangeObserver observer(model, node);
206 model->GetFavicon(node);
207 observer.WaitForGetFavicon();
209 EXPECT_TRUE(node->is_favicon_loaded());
210 EXPECT_FALSE(model->GetFavicon(node).IsEmpty());
211 return FaviconData(model->GetFavicon(node), node->icon_url());
214 // Sets the favicon for |profile| and |node|. |profile| may be
215 // |test()->verifier()|.
216 void SetFaviconImpl(Profile* profile,
217 const BookmarkNode* node,
218 const GURL& icon_url,
219 const gfx::Image& image,
220 bookmarks_helper::FaviconSource favicon_source) {
221 BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile);
223 FaviconChangeObserver observer(model, node);
224 FaviconService* favicon_service =
225 FaviconServiceFactory::GetForProfile(profile,
226 Profile::EXPLICIT_ACCESS);
227 if (favicon_source == bookmarks_helper::FROM_UI) {
228 favicon_service->SetFavicons(node->url(),
229 icon_url,
230 chrome::FAVICON,
231 image);
232 } else {
233 browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon(
234 node, profile, icon_url, image.As1xPNGBytes());
237 // Wait for the favicon for |node| to be invalidated.
238 observer.WaitForSetFavicon();
239 // Wait for the BookmarkModel to fetch the updated favicon and for the new
240 // favicon to be sent to BookmarkChangeProcessor.
241 GetFaviconData(model, node);
244 // Wait for all currently scheduled tasks on the history thread for all
245 // profiles to complete and any notifications sent to the UI thread to have
246 // finished processing.
247 void WaitForHistoryToProcessPendingTasks() {
248 // Skip waiting for history to complete for tests without favicons.
249 if (!urls_with_favicons_)
250 return;
252 std::vector<Profile*> profiles_which_need_to_wait;
253 if (test()->use_verifier())
254 profiles_which_need_to_wait.push_back(test()->verifier());
255 for (int i = 0; i < test()->num_clients(); ++i)
256 profiles_which_need_to_wait.push_back(test()->GetProfile(i));
258 for (size_t i = 0; i < profiles_which_need_to_wait.size(); ++i) {
259 Profile* profile = profiles_which_need_to_wait[i];
260 HistoryService* history_service =
261 HistoryServiceFactory::GetForProfileWithoutCreating(profile);
262 base::WaitableEvent done(false, false);
263 CancelableRequestConsumer request_consumer;
264 history_service->ScheduleDBTask(new HistoryEmptyTask(&done),
265 &request_consumer);
266 done.Wait();
268 // Wait such that any notifications broadcast from one of the history threads
269 // to the UI thread are processed.
270 content::RunAllPendingInMessageLoop();
273 // Checks if the favicon in |node_a| from |model_a| matches that of |node_b|
274 // from |model_b|. Returns true if they match.
275 bool FaviconsMatch(BookmarkModel* model_a,
276 BookmarkModel* model_b,
277 const BookmarkNode* node_a,
278 const BookmarkNode* node_b) {
279 FaviconData favicon_data_a = GetFaviconData(model_a, node_a);
280 FaviconData favicon_data_b = GetFaviconData(model_b, node_b);
282 if (favicon_data_a.icon_url != favicon_data_b.icon_url)
283 return false;
285 gfx::Image image_a = favicon_data_a.image;
286 gfx::Image image_b = favicon_data_b.image;
288 if (image_a.IsEmpty() && image_b.IsEmpty())
289 return true; // Two empty images are equivalent.
291 if (image_a.IsEmpty() != image_b.IsEmpty())
292 return false;
294 // Compare only the 1x bitmaps as only those are synced.
295 SkBitmap bitmap_a = image_a.AsImageSkia().GetRepresentation(
296 1.0f).sk_bitmap();
297 SkBitmap bitmap_b = image_b.AsImageSkia().GetRepresentation(
298 1.0f).sk_bitmap();
299 return FaviconBitmapsMatch(bitmap_a, bitmap_b);
302 // Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|.
303 // Returns true if they are all equal.
304 bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) {
305 if (node_a == NULL || node_b == NULL)
306 return node_a == node_b;
307 if (node_a->is_folder() != node_b->is_folder()) {
308 LOG(ERROR) << "Cannot compare folder with bookmark";
309 return false;
311 if (node_a->GetTitle() != node_b->GetTitle()) {
312 LOG(ERROR) << "Title mismatch: " << node_a->GetTitle() << " vs. "
313 << node_b->GetTitle();
314 return false;
316 if (node_a->url() != node_b->url()) {
317 LOG(ERROR) << "URL mismatch: " << node_a->url() << " vs. "
318 << node_b->url();
319 return false;
321 if (node_a->parent()->GetIndexOf(node_a) !=
322 node_b->parent()->GetIndexOf(node_b)) {
323 LOG(ERROR) << "Index mismatch: "
324 << node_a->parent()->GetIndexOf(node_a) << " vs. "
325 << node_b->parent()->GetIndexOf(node_b);
326 return false;
328 return true;
331 // Checks if the hierarchies in |model_a| and |model_b| are equivalent in
332 // terms of the data model and favicon. Returns true if they both match.
333 // Note: Some peripheral fields like creation times are allowed to mismatch.
334 bool BookmarkModelsMatch(BookmarkModel* model_a, BookmarkModel* model_b) {
335 bool ret_val = true;
336 ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node());
337 ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node());
338 while (iterator_a.has_next()) {
339 const BookmarkNode* node_a = iterator_a.Next();
340 if (!iterator_b.has_next()) {
341 LOG(ERROR) << "Models do not match.";
342 return false;
344 const BookmarkNode* node_b = iterator_b.Next();
345 ret_val = ret_val && NodesMatch(node_a, node_b);
346 if (node_a->is_folder() || node_b->is_folder())
347 continue;
348 ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b);
350 ret_val = ret_val && (!iterator_b.has_next());
351 return ret_val;
354 // Finds the node in the verifier bookmark model that corresponds to
355 // |foreign_node| in |foreign_model| and stores its address in |result|.
356 void FindNodeInVerifier(BookmarkModel* foreign_model,
357 const BookmarkNode* foreign_node,
358 const BookmarkNode** result) {
359 // Climb the tree.
360 std::stack<int> path;
361 const BookmarkNode* walker = foreign_node;
362 while (walker != foreign_model->root_node()) {
363 path.push(walker->parent()->GetIndexOf(walker));
364 walker = walker->parent();
367 // Swing over to the other tree.
368 walker = bookmarks_helper::GetVerifierBookmarkModel()->root_node();
370 // Climb down.
371 while (!path.empty()) {
372 ASSERT_TRUE(walker->is_folder());
373 ASSERT_LT(path.top(), walker->child_count());
374 walker = walker->GetChild(path.top());
375 path.pop();
378 ASSERT_TRUE(NodesMatch(foreign_node, walker));
379 *result = walker;
382 } // namespace
385 namespace bookmarks_helper {
387 BookmarkModel* GetBookmarkModel(int index) {
388 return BookmarkModelFactory::GetForProfile(test()->GetProfile(index));
391 const BookmarkNode* GetBookmarkBarNode(int index) {
392 return GetBookmarkModel(index)->bookmark_bar_node();
395 const BookmarkNode* GetOtherNode(int index) {
396 return GetBookmarkModel(index)->other_node();
399 const BookmarkNode* GetSyncedBookmarksNode(int index) {
400 return GetBookmarkModel(index)->mobile_node();
403 BookmarkModel* GetVerifierBookmarkModel() {
404 return BookmarkModelFactory::GetForProfile(test()->verifier());
407 const BookmarkNode* AddURL(int profile,
408 const std::wstring& title,
409 const GURL& url) {
410 return AddURL(profile, GetBookmarkBarNode(profile), 0, title, url);
413 const BookmarkNode* AddURL(int profile,
414 int index,
415 const std::wstring& title,
416 const GURL& url) {
417 return AddURL(profile, GetBookmarkBarNode(profile), index, title, url);
420 const BookmarkNode* AddURL(int profile,
421 const BookmarkNode* parent,
422 int index,
423 const std::wstring& title,
424 const GURL& url) {
425 if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) {
426 LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to "
427 << "Profile " << profile;
428 return NULL;
430 const BookmarkNode* result = GetBookmarkModel(profile)->
431 AddURL(parent, index, base::WideToUTF16(title), url);
432 if (!result) {
433 LOG(ERROR) << "Could not add bookmark " << title << " to Profile "
434 << profile;
435 return NULL;
437 if (test()->use_verifier()) {
438 const BookmarkNode* v_parent = NULL;
439 FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent);
440 const BookmarkNode* v_node = GetVerifierBookmarkModel()->
441 AddURL(v_parent, index, base::WideToUTF16(title), url);
442 if (!v_node) {
443 LOG(ERROR) << "Could not add bookmark " << title << " to the verifier";
444 return NULL;
446 EXPECT_TRUE(NodesMatch(v_node, result));
448 return result;
451 const BookmarkNode* AddFolder(int profile,
452 const std::wstring& title) {
453 return AddFolder(profile, GetBookmarkBarNode(profile), 0, title);
456 const BookmarkNode* AddFolder(int profile,
457 int index,
458 const std::wstring& title) {
459 return AddFolder(profile, GetBookmarkBarNode(profile), index, title);
462 const BookmarkNode* AddFolder(int profile,
463 const BookmarkNode* parent,
464 int index,
465 const std::wstring& title) {
466 if (GetBookmarkModel(profile)->GetNodeByID(parent->id()) != parent) {
467 LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to "
468 << "Profile " << profile;
469 return NULL;
471 const BookmarkNode* result = GetBookmarkModel(profile)->AddFolder(
472 parent, index, base::WideToUTF16(title));
473 EXPECT_TRUE(result);
474 if (!result) {
475 LOG(ERROR) << "Could not add folder " << title << " to Profile "
476 << profile;
477 return NULL;
479 if (test()->use_verifier()) {
480 const BookmarkNode* v_parent = NULL;
481 FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent);
482 const BookmarkNode* v_node = GetVerifierBookmarkModel()->AddFolder(
483 v_parent, index, base::WideToUTF16(title));
484 if (!v_node) {
485 LOG(ERROR) << "Could not add folder " << title << " to the verifier";
486 return NULL;
488 EXPECT_TRUE(NodesMatch(v_node, result));
490 return result;
493 void SetTitle(int profile,
494 const BookmarkNode* node,
495 const std::wstring& new_title) {
496 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node)
497 << "Node " << node->GetTitle() << " does not belong to "
498 << "Profile " << profile;
499 if (test()->use_verifier()) {
500 const BookmarkNode* v_node = NULL;
501 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node);
502 GetVerifierBookmarkModel()->SetTitle(v_node, base::WideToUTF16(new_title));
504 GetBookmarkModel(profile)->SetTitle(node, base::WideToUTF16(new_title));
507 void SetFavicon(int profile,
508 const BookmarkNode* node,
509 const GURL& icon_url,
510 const gfx::Image& image,
511 FaviconSource favicon_source) {
512 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node)
513 << "Node " << node->GetTitle() << " does not belong to "
514 << "Profile " << profile;
515 ASSERT_EQ(BookmarkNode::URL, node->type())
516 << "Node " << node->GetTitle() << " must be a url.";
517 if (urls_with_favicons_ == NULL)
518 urls_with_favicons_ = new std::set<GURL>();
519 urls_with_favicons_->insert(node->url());
520 if (test()->use_verifier()) {
521 const BookmarkNode* v_node = NULL;
522 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node);
523 SetFaviconImpl(test()->verifier(), v_node, icon_url, image, favicon_source);
525 SetFaviconImpl(test()->GetProfile(profile), node, icon_url, image,
526 favicon_source);
529 const BookmarkNode* SetURL(int profile,
530 const BookmarkNode* node,
531 const GURL& new_url) {
532 if (GetBookmarkModel(profile)->GetNodeByID(node->id()) != node) {
533 LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to "
534 << "Profile " << profile;
535 return NULL;
537 if (test()->use_verifier()) {
538 const BookmarkNode* v_node = NULL;
539 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node);
540 if (v_node->is_url())
541 GetVerifierBookmarkModel()->SetURL(v_node, new_url);
543 if (node->is_url())
544 GetBookmarkModel(profile)->SetURL(node, new_url);
545 return node;
548 void Move(int profile,
549 const BookmarkNode* node,
550 const BookmarkNode* new_parent,
551 int index) {
552 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(node->id()), node)
553 << "Node " << node->GetTitle() << " does not belong to "
554 << "Profile " << profile;
555 if (test()->use_verifier()) {
556 const BookmarkNode* v_new_parent = NULL;
557 const BookmarkNode* v_node = NULL;
558 FindNodeInVerifier(GetBookmarkModel(profile), new_parent, &v_new_parent);
559 FindNodeInVerifier(GetBookmarkModel(profile), node, &v_node);
560 GetVerifierBookmarkModel()->Move(v_node, v_new_parent, index);
562 GetBookmarkModel(profile)->Move(node, new_parent, index);
565 void Remove(int profile,
566 const BookmarkNode* parent,
567 int index) {
568 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent)
569 << "Node " << parent->GetTitle() << " does not belong to "
570 << "Profile " << profile;
571 if (test()->use_verifier()) {
572 const BookmarkNode* v_parent = NULL;
573 FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent);
574 ASSERT_TRUE(NodesMatch(parent->GetChild(index), v_parent->GetChild(index)));
575 GetVerifierBookmarkModel()->Remove(v_parent, index);
577 GetBookmarkModel(profile)->Remove(parent, index);
580 void RemoveAll(int profile) {
581 if (test()->use_verifier()) {
582 const BookmarkNode* root_node = GetVerifierBookmarkModel()->root_node();
583 for (int i = 0; i < root_node->child_count(); ++i) {
584 const BookmarkNode* permanent_node = root_node->GetChild(i);
585 for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
586 GetVerifierBookmarkModel()->Remove(permanent_node, j);
590 GetBookmarkModel(profile)->RemoveAll();
593 void SortChildren(int profile, const BookmarkNode* parent) {
594 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent)
595 << "Node " << parent->GetTitle() << " does not belong to "
596 << "Profile " << profile;
597 if (test()->use_verifier()) {
598 const BookmarkNode* v_parent = NULL;
599 FindNodeInVerifier(GetBookmarkModel(profile), parent, &v_parent);
600 GetVerifierBookmarkModel()->SortChildren(v_parent);
602 GetBookmarkModel(profile)->SortChildren(parent);
605 void ReverseChildOrder(int profile, const BookmarkNode* parent) {
606 ASSERT_EQ(GetBookmarkModel(profile)->GetNodeByID(parent->id()), parent)
607 << "Node " << parent->GetTitle() << " does not belong to "
608 << "Profile " << profile;
609 int child_count = parent->child_count();
610 if (child_count <= 0)
611 return;
612 for (int index = 0; index < child_count; ++index) {
613 Move(profile, parent->GetChild(index), parent, child_count - index);
617 bool ModelMatchesVerifier(int profile) {
618 if (!test()->use_verifier()) {
619 LOG(ERROR) << "Illegal to call ModelMatchesVerifier() after "
620 << "DisableVerifier(). Use ModelsMatch() instead.";
621 return false;
623 return BookmarkModelsMatch(GetVerifierBookmarkModel(),
624 GetBookmarkModel(profile));
627 bool AllModelsMatchVerifier() {
628 // Ensure that all tasks have finished processing on the history thread
629 // and that any notifications the history thread may have sent have been
630 // processed before comparing models.
631 WaitForHistoryToProcessPendingTasks();
633 for (int i = 0; i < test()->num_clients(); ++i) {
634 if (!ModelMatchesVerifier(i)) {
635 LOG(ERROR) << "Model " << i << " does not match the verifier.";
636 return false;
639 return true;
642 bool ModelsMatch(int profile_a, int profile_b) {
643 return BookmarkModelsMatch(GetBookmarkModel(profile_a),
644 GetBookmarkModel(profile_b));
647 bool AllModelsMatch() {
648 // Ensure that all tasks have finished processing on the history thread
649 // and that any notifications the history thread may have sent have been
650 // processed before comparing models.
651 WaitForHistoryToProcessPendingTasks();
653 for (int i = 1; i < test()->num_clients(); ++i) {
654 if (!ModelsMatch(0, i)) {
655 LOG(ERROR) << "Model " << i << " does not match Model 0.";
656 return false;
659 return true;
662 bool ContainsDuplicateBookmarks(int profile) {
663 ui::TreeNodeIterator<const BookmarkNode> iterator(
664 GetBookmarkModel(profile)->root_node());
665 while (iterator.has_next()) {
666 const BookmarkNode* node = iterator.Next();
667 if (node->is_folder())
668 continue;
669 std::vector<const BookmarkNode*> nodes;
670 GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes);
671 EXPECT_TRUE(nodes.size() >= 1);
672 for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin();
673 it != nodes.end(); ++it) {
674 if (node->id() != (*it)->id() &&
675 node->parent() == (*it)->parent() &&
676 node->GetTitle() == (*it)->GetTitle()){
677 return true;
681 return false;
684 bool HasNodeWithURL(int profile, const GURL& url) {
685 std::vector<const BookmarkNode*> nodes;
686 GetBookmarkModel(profile)->GetNodesByURL(url, &nodes);
687 return !nodes.empty();
690 const BookmarkNode* GetUniqueNodeByURL(int profile, const GURL& url) {
691 std::vector<const BookmarkNode*> nodes;
692 GetBookmarkModel(profile)->GetNodesByURL(url, &nodes);
693 EXPECT_EQ(1U, nodes.size());
694 if (nodes.empty())
695 return NULL;
696 return nodes[0];
699 int CountBookmarksWithTitlesMatching(int profile, const std::wstring& title) {
700 return CountNodesWithTitlesMatching(GetBookmarkModel(profile),
701 BookmarkNode::URL,
702 base::WideToUTF16(title));
705 int CountFoldersWithTitlesMatching(int profile, const std::wstring& title) {
706 return CountNodesWithTitlesMatching(GetBookmarkModel(profile),
707 BookmarkNode::FOLDER,
708 base::WideToUTF16(title));
711 gfx::Image CreateFavicon(SkColor color) {
712 const int dip_width = 16;
713 const int dip_height = 16;
714 std::vector<ui::ScaleFactor> favicon_scale_factors =
715 FaviconUtil::GetFaviconScaleFactors();
716 gfx::ImageSkia favicon;
717 for (size_t i = 0; i < favicon_scale_factors.size(); ++i) {
718 float scale = ui::GetImageScale(favicon_scale_factors[i]);
719 int pixel_width = dip_width * scale;
720 int pixel_height = dip_height * scale;
721 SkBitmap bmp;
722 bmp.setConfig(SkBitmap::kARGB_8888_Config, pixel_width, pixel_height);
723 bmp.allocPixels();
724 bmp.eraseColor(color);
725 favicon.AddRepresentation(
726 gfx::ImageSkiaRep(bmp,
727 ui::GetImageScale(favicon_scale_factors[i])));
729 return gfx::Image(favicon);
732 gfx::Image Create1xFaviconFromPNGFile(const std::string& path) {
733 const char* kPNGExtension = ".png";
734 if (!EndsWith(path, kPNGExtension, false))
735 return gfx::Image();
737 base::FilePath full_path;
738 if (!PathService::Get(chrome::DIR_TEST_DATA, &full_path))
739 return gfx::Image();
741 full_path = full_path.AppendASCII("sync").AppendASCII(path);
742 std::string contents;
743 base::ReadFileToString(full_path, &contents);
744 return gfx::Image::CreateFrom1xPNGBytes(
745 base::RefCountedString::TakeString(&contents));
748 std::string IndexedURL(int i) {
749 return base::StringPrintf("http://www.host.ext:1234/path/filename/%d", i);
752 std::wstring IndexedURLTitle(int i) {
753 return base::StringPrintf(L"URL Title %d", i);
756 std::wstring IndexedFolderName(int i) {
757 return base::StringPrintf(L"Folder Name %d", i);
760 std::wstring IndexedSubfolderName(int i) {
761 return base::StringPrintf(L"Subfolder Name %d", i);
764 std::wstring IndexedSubsubfolderName(int i) {
765 return base::StringPrintf(L"Subsubfolder Name %d", i);
768 } // namespace bookmarks_helper