bookmarks_helper.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/test/integration/bookmarks_helper.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/waitable_event.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_observer.h" 190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/bookmarks/bookmark_utils.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_service_factory.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/favicon/favicon_util.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_db_task.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_service_factory.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_types.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync/glue/bookmark_change_processor.h" 27a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/sync/test/integration/multi_client_status_change_checker.h" 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/test/integration/sync_datatype_helper.h" 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/sync/test/integration/sync_test.h" 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_paths.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/ui_test_utils.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/models/tree_node_iterator.h" 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image_skia.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sync_datatype_helper::test; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// History task which runs all pending tasks on the history thread and 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// signals when the tasks have completed. 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class HistoryEmptyTask : public history::HistoryDBTask { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit HistoryEmptyTask(base::WaitableEvent* done) : done_(done) {} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool RunOnDBThread(history::HistoryBackend* backend, 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) history::HistoryDatabase* db) OVERRIDE { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RunAllPendingInMessageLoop(); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done_->Signal(); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void DoneRunOnMainThread() OVERRIDE {} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~HistoryEmptyTask() {} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WaitableEvent* done_; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class used to wait for changes to take effect on the favicon of a 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// particular bookmark node in a particular bookmark model. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FaviconChangeObserver : public BookmarkModelObserver { 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconChangeObserver(BookmarkModel* model, const BookmarkNode* node) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : model_(model), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_(node), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_for_load_(false) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->AddObserver(this); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~FaviconChangeObserver() { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_->RemoveObserver(this); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WaitForGetFavicon() { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_for_load_ = true; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RunMessageLoop(); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(node_->is_favicon_loaded()); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_FALSE(model_->GetFavicon(node_).IsEmpty()); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void WaitForSetFavicon() { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_for_load_ = false; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RunMessageLoop(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void BookmarkModelLoaded(BookmarkModel* model, 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool ids_reassigned) OVERRIDE {} 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeMoved(BookmarkModel* model, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* old_parent, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_index, 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* new_parent, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_index) OVERRIDE {} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeAdded(BookmarkModel* model, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* parent, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) OVERRIDE {} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeRemoved(BookmarkModel* model, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* parent, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int old_index, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node) OVERRIDE {} 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void BookmarkAllNodesRemoved(BookmarkModel* model) OVERRIDE {} 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeChanged(BookmarkModel* model, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node) OVERRIDE { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model == model_ && node == node_) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->GetFavicon(node); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeChildrenReordered( 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModel* model, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node) OVERRIDE {} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void BookmarkNodeFaviconChanged( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModel* model, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node) OVERRIDE { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (model == model_ && node == node_) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!wait_for_load_ || (wait_for_load_ && node->is_favicon_loaded())) 11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoopForUI::current()->Quit(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModel* model_; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node_; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool wait_for_load_; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(FaviconChangeObserver); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A collection of URLs for which we have added favicons. Since loading a 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// favicon is an asynchronous operation and doesn't necessarily invoke a 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// callback, this collection is used to determine if we must wait for a URL's 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// favicon to load or not. 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::set<GURL>* urls_with_favicons_ = NULL; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the number of nodes of node type |node_type| in |model| whose 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// titles match the string |title|. 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CountNodesWithTitlesMatching(BookmarkModel* model, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::Type node_type, 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& title) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::TreeNodeIterator<const BookmarkNode> iterator(model->root_node()); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk through the model tree looking for bookmark nodes of node type 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |node_type| whose titles match |title|. 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int count = 0; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (iterator.has_next()) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node = iterator.Next(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((node->type() == node_type) && (node->GetTitle() == title)) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++count; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return count; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks if the favicon data in |bitmap_a| and |bitmap_b| are equivalent. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if they match. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconBitmapsMatch(const SkBitmap& bitmap_a, const SkBitmap& bitmap_b) { 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (bitmap_a.getSize() == 0U && bitmap_b.getSize() == 0U) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((bitmap_a.getSize() != bitmap_b.getSize()) || 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (bitmap_a.width() != bitmap_b.width()) || 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (bitmap_a.height() != bitmap_b.height())) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Favicon size mismatch: " << bitmap_a.getSize() << " (" 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << bitmap_a.width() << "x" << bitmap_a.height() << ") vs. " 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << bitmap_b.getSize() << " (" << bitmap_b.width() << "x" 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << bitmap_b.height() << ")"; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkAutoLockPixels bitmap_lock_a(bitmap_a); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkAutoLockPixels bitmap_lock_b(bitmap_b); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* node_pixel_addr_a = bitmap_a.getPixels(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(node_pixel_addr_a); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* node_pixel_addr_b = bitmap_b.getPixels(); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(node_pixel_addr_b); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (memcmp(node_pixel_addr_a, node_pixel_addr_b, bitmap_a.getSize()) != 0) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Favicon bitmap mismatch"; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Represents a favicon image and the icon URL associated with it. 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct FaviconData { 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconData() { 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconData(const gfx::Image& favicon_image, 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& favicon_url) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : image(favicon_image), 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) icon_url(favicon_url) { 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ~FaviconData() { 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Image image; 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GURL icon_url; 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Gets the favicon and icon URL associated with |node| in |model|. 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FaviconData GetFaviconData(BookmarkModel* model, 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const BookmarkNode* node) { 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a favicon wasn't explicitly set for a particular URL, simply return its 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // blank favicon. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!urls_with_favicons_ || 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) urls_with_favicons_->find(node->url()) == urls_with_favicons_->end()) { 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FaviconData(); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a favicon was explicitly set, we may need to wait for it to be loaded 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // via BookmarkModel::GetFavicon(), which is an asynchronous operation. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!node->is_favicon_loaded()) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconChangeObserver observer(model, node); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model->GetFavicon(node); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer.WaitForGetFavicon(); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(node->is_favicon_loaded()); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_FALSE(model->GetFavicon(node).IsEmpty()); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FaviconData(model->GetFavicon(node), node->icon_url()); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sets the favicon for |profile| and |node|. |profile| may be 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |test()->verifier()|. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetFaviconImpl(Profile* profile, 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node, 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& icon_url, 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Image& image, 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bookmarks_helper::FaviconSource favicon_source) { 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconChangeObserver observer(model, node); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconService* favicon_service = 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FaviconServiceFactory::GetForProfile(profile, 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile::EXPLICIT_ACCESS); 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (favicon_source == bookmarks_helper::FROM_UI) { 2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch favicon_service->SetFavicons( 2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch node->url(), icon_url, favicon_base::FAVICON, image); 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) browser_sync::BookmarkChangeProcessor::ApplyBookmarkFavicon( 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) node, profile, icon_url, image.As1xPNGBytes()); 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for the favicon for |node| to be invalidated. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) observer.WaitForSetFavicon(); 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for the BookmarkModel to fetch the updated favicon and for the new 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // favicon to be sent to BookmarkChangeProcessor. 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetFaviconData(model, node); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wait for all currently scheduled tasks on the history thread for all 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// profiles to complete and any notifications sent to the UI thread to have 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finished processing. 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WaitForHistoryToProcessPendingTasks() { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip waiting for history to complete for tests without favicons. 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!urls_with_favicons_) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<Profile*> profiles_which_need_to_wait; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiles_which_need_to_wait.push_back(test()->verifier()); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < test()->num_clients(); ++i) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profiles_which_need_to_wait.push_back(test()->GetProfile(i)); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < profiles_which_need_to_wait.size(); ++i) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = profiles_which_need_to_wait[i]; 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryService* history_service = 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HistoryServiceFactory::GetForProfileWithoutCreating(profile); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WaitableEvent done(false, false); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CancelableRequestConsumer request_consumer; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_service->ScheduleDBTask(new HistoryEmptyTask(&done), 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &request_consumer); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done.Wait(); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait such that any notifications broadcast from one of the history threads 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to the UI thread are processed. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::RunAllPendingInMessageLoop(); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks if the favicon in |node_a| from |model_a| matches that of |node_b| 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from |model_b|. Returns true if they match. 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FaviconsMatch(BookmarkModel* model_a, 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkModel* model_b, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node_a, 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node_b) { 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconData favicon_data_a = GetFaviconData(model_a, node_a); 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconData favicon_data_b = GetFaviconData(model_b, node_b); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (favicon_data_a.icon_url != favicon_data_b.icon_url) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Image image_a = favicon_data_a.image; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Image image_b = favicon_data_b.image; 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_a.IsEmpty() && image_b.IsEmpty()) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; // Two empty images are equivalent. 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (image_a.IsEmpty() != image_b.IsEmpty()) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Compare only the 1x bitmaps as only those are synced. 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkBitmap bitmap_a = image_a.AsImageSkia().GetRepresentation( 29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1.0f).sk_bitmap(); 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkBitmap bitmap_b = image_b.AsImageSkia().GetRepresentation( 29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1.0f).sk_bitmap(); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return FaviconBitmapsMatch(bitmap_a, bitmap_b); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Does a deep comparison of BookmarkNode fields in |model_a| and |model_b|. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if they are all equal. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NodesMatch(const BookmarkNode* node_a, const BookmarkNode* node_b) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a == NULL || node_b == NULL) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return node_a == node_b; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a->is_folder() != node_b->is_folder()) { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cannot compare folder with bookmark"; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a->GetTitle() != node_b->GetTitle()) { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Title mismatch: " << node_a->GetTitle() << " vs. " 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << node_b->GetTitle(); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a->url() != node_b->url()) { 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "URL mismatch: " << node_a->url() << " vs. " 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << node_b->url(); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a->parent()->GetIndexOf(node_a) != 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_b->parent()->GetIndexOf(node_b)) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Index mismatch: " 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << node_a->parent()->GetIndexOf(node_a) << " vs. " 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << node_b->parent()->GetIndexOf(node_b); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks if the hierarchies in |model_a| and |model_b| are equivalent in 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// terms of the data model and favicon. Returns true if they both match. 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note: Some peripheral fields like creation times are allowed to mismatch. 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkModelsMatch(BookmarkModel* model_a, BookmarkModel* model_b) { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ret_val = true; 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::TreeNodeIterator<const BookmarkNode> iterator_a(model_a->root_node()); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::TreeNodeIterator<const BookmarkNode> iterator_b(model_b->root_node()); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (iterator_a.has_next()) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node_a = iterator_a.Next(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!iterator_b.has_next()) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Models do not match."; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node_b = iterator_b.Next(); 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_val = ret_val && NodesMatch(node_a, node_b); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_a->is_folder() || node_b->is_folder()) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_val = ret_val && FaviconsMatch(model_a, model_b, node_a, node_b); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret_val = ret_val && (!iterator_b.has_next()); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret_val; 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Finds the node in the verifier bookmark model that corresponds to 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |foreign_node| in |foreign_model| and stores its address in |result|. 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FindNodeInVerifier(BookmarkModel* foreign_model, 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* foreign_node, 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode** result) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Climb the tree. 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::stack<int> path; 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* walker = foreign_node; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (walker != foreign_model->root_node()) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.push(walker->parent()->GetIndexOf(walker)); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) walker = walker->parent(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swing over to the other tree. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) walker = bookmarks_helper::GetVerifierBookmarkModel()->root_node(); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Climb down. 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!path.empty()) { 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(walker->is_folder()); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_LT(path.top(), walker->child_count()); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) walker = walker->GetChild(path.top()); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path.pop(); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(NodesMatch(foreign_node, walker)); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = walker; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace bookmarks_helper { 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkModel* GetBookmarkModel(int index) { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BookmarkModelFactory::GetForProfile(test()->GetProfile(index)); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* GetBookmarkBarNode(int index) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetBookmarkModel(index)->bookmark_bar_node(); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* GetOtherNode(int index) { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetBookmarkModel(index)->other_node(); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* GetSyncedBookmarksNode(int index) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetBookmarkModel(index)->mobile_node(); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkModel* GetVerifierBookmarkModel() { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BookmarkModelFactory::GetForProfile(test()->verifier()); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddURL(int profile, 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title, 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url) { 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddURL(profile, GetBookmarkBarNode(profile), 0, title, url); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddURL(int profile, 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title, 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url) { 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddURL(profile, GetBookmarkBarNode(profile), index, title, url); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddURL(int profile, 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* parent, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url) { 4250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 4260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (GetBookmarkNodeByID(model, parent->id()) != parent) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode* result = 4320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->AddURL(parent, index, base::WideToUTF16(title), url); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not add bookmark " << title << " to Profile " 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << profile; 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_parent = NULL; 4400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, parent, &v_parent); 4410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode* v_node = GetVerifierBookmarkModel()->AddURL( 4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch v_parent, index, base::WideToUTF16(title), url); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!v_node) { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not add bookmark " << title << " to the verifier"; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(NodesMatch(v_node, result)); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddFolder(int profile, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title) { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddFolder(profile, GetBookmarkBarNode(profile), 0, title); 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddFolder(int profile, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title) { 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return AddFolder(profile, GetBookmarkBarNode(profile), index, title); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* AddFolder(int profile, 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* parent, 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index, 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& title) { 4670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 4680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (GetBookmarkNodeByID(model, parent->id()) != parent) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Node " << parent->GetTitle() << " does not belong to " 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const BookmarkNode* result = 4740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->AddFolder(parent, index, base::WideToUTF16(title)); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(result); 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!result) { 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not add folder " << title << " to Profile " 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << profile; 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_parent = NULL; 4830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, parent, &v_parent); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_node = GetVerifierBookmarkModel()->AddFolder( 4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) v_parent, index, base::WideToUTF16(title)); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!v_node) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not add folder " << title << " to the verifier"; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(NodesMatch(v_node, result)); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetTitle(int profile, 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node, 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::wstring& new_title) { 4980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 4990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(model, node->id()), node) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << node->GetTitle() << " does not belong to " 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_node = NULL; 5040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, node, &v_node); 5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetVerifierBookmarkModel()->SetTitle(v_node, base::WideToUTF16(new_title)); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->SetTitle(node, base::WideToUTF16(new_title)); 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetFavicon(int profile, 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node, 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const GURL& icon_url, 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Image& image, 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconSource favicon_source) { 5150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 5160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(model, node->id()), node) 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << node->GetTitle() << " does not belong to " 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 5190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(BookmarkNode::URL, node->type()) << "Node " << node->GetTitle() 5200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch << " must be a url."; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (urls_with_favicons_ == NULL) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) urls_with_favicons_ = new std::set<GURL>(); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) urls_with_favicons_->insert(node->url()); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_node = NULL; 5260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, node, &v_node); 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetFaviconImpl(test()->verifier(), v_node, icon_url, image, favicon_source); 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetFaviconImpl(test()->GetProfile(profile), node, icon_url, image, 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) favicon_source); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* SetURL(int profile, 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node, 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& new_url) { 5360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 5370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (GetBookmarkNodeByID(model, node->id()) != node) { 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Node " << node->GetTitle() << " does not belong to " 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_node = NULL; 5440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, node, &v_node); 545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (v_node->is_url()) 546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) GetVerifierBookmarkModel()->SetURL(v_node, new_url); 547868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 548868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (node->is_url()) 5490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->SetURL(node, new_url); 550868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return node; 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Move(int profile, 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node, 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* new_parent, 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int index) { 5570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 5580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(model, node->id()), node) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << node->GetTitle() << " does not belong to " 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_new_parent = NULL; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_node = NULL; 5640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, new_parent, &v_new_parent); 5650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, node, &v_node); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetVerifierBookmarkModel()->Move(v_node, v_new_parent, index); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->Move(node, new_parent, index); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid Remove(int profile, const BookmarkNode* parent, int index) { 5720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 5730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(model, parent->id()), parent) 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << parent->GetTitle() << " does not belong to " 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_parent = NULL; 5780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, parent, &v_parent); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_TRUE(NodesMatch(parent->GetChild(index), v_parent->GetChild(index))); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetVerifierBookmarkModel()->Remove(v_parent, index); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->Remove(parent, index); 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void RemoveAll(int profile) { 586c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (test()->use_verifier()) { 587c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const BookmarkNode* root_node = GetVerifierBookmarkModel()->root_node(); 588c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int i = 0; i < root_node->child_count(); ++i) { 589c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const BookmarkNode* permanent_node = root_node->GetChild(i); 590c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int j = permanent_node->child_count() - 1; j >= 0; --j) { 591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) GetVerifierBookmarkModel()->Remove(permanent_node, j); 592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) GetBookmarkModel(profile)->RemoveAll(); 596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SortChildren(int profile, const BookmarkNode* parent) { 5990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch BookmarkModel* model = GetBookmarkModel(profile); 6000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(model, parent->id()), parent) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << parent->GetTitle() << " does not belong to " 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (test()->use_verifier()) { 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* v_parent = NULL; 6050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch FindNodeInVerifier(model, parent, &v_parent); 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetVerifierBookmarkModel()->SortChildren(v_parent); 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch model->SortChildren(parent); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ReverseChildOrder(int profile, const BookmarkNode* parent) { 6120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ASSERT_EQ(GetBookmarkNodeByID(GetBookmarkModel(profile), parent->id()), 6130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch parent) 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Node " << parent->GetTitle() << " does not belong to " 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Profile " << profile; 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int child_count = parent->child_count(); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (child_count <= 0) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int index = 0; index < child_count; ++index) { 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Move(profile, parent->GetChild(index), parent, child_count - index); 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ModelMatchesVerifier(int profile) { 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!test()->use_verifier()) { 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Illegal to call ModelMatchesVerifier() after " 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "DisableVerifier(). Use ModelsMatch() instead."; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BookmarkModelsMatch(GetVerifierBookmarkModel(), 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile)); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AllModelsMatchVerifier() { 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that all tasks have finished processing on the history thread 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and that any notifications the history thread may have sent have been 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // processed before comparing models. 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForHistoryToProcessPendingTasks(); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < test()->num_clients(); ++i) { 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ModelMatchesVerifier(i)) { 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Model " << i << " does not match the verifier."; 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ModelsMatch(int profile_a, int profile_b) { 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return BookmarkModelsMatch(GetBookmarkModel(profile_a), 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile_b)); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AllModelsMatch() { 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that all tasks have finished processing on the history thread 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and that any notifications the history thread may have sent have been 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // processed before comparing models. 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WaitForHistoryToProcessPendingTasks(); 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 1; i < test()->num_clients(); ++i) { 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ModelsMatch(0, i)) { 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Model " << i << " does not match Model 0."; 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 669a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochnamespace { 670a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 671a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Helper class used in the implementation of AwaitAllModelsMatch. 672a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochclass AllModelsMatchChecker : public MultiClientStatusChangeChecker { 673a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch public: 674a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch AllModelsMatchChecker(); 675a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch virtual ~AllModelsMatchChecker(); 676a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 677a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch virtual bool IsExitConditionSatisfied() OVERRIDE; 678a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch virtual std::string GetDebugMessage() const OVERRIDE; 679a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}; 680a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 681a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochAllModelsMatchChecker::AllModelsMatchChecker() 682a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch : MultiClientStatusChangeChecker( 683a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch sync_datatype_helper::test()->GetSyncServices()) {} 684a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 685a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochAllModelsMatchChecker::~AllModelsMatchChecker() {} 686a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 687a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool AllModelsMatchChecker::IsExitConditionSatisfied() { 688a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return AllModelsMatch(); 689a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 690a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 691a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochstd::string AllModelsMatchChecker::GetDebugMessage() const { 692a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return "Waiting for matching models"; 693a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 694a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 695a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} // namespace 696a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 697a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool AwaitAllModelsMatch() { 698a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch AllModelsMatchChecker checker; 699a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch checker.Wait(); 700a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return !checker.TimedOut(); 701a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 702a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 703a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ContainsDuplicateBookmarks(int profile) { 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::TreeNodeIterator<const BookmarkNode> iterator( 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile)->root_node()); 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (iterator.has_next()) { 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const BookmarkNode* node = iterator.Next(); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->is_folder()) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*> nodes; 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile)->GetNodesByURL(node->url(), &nodes); 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_TRUE(nodes.size() >= 1); 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<const BookmarkNode*>::const_iterator it = nodes.begin(); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != nodes.end(); ++it) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node->id() != (*it)->id() && 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->parent() == (*it)->parent() && 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->GetTitle() == (*it)->GetTitle()){ 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasNodeWithURL(int profile, const GURL& url) { 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*> nodes; 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile)->GetNodesByURL(url, &nodes); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !nodes.empty(); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* GetUniqueNodeByURL(int profile, const GURL& url) { 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<const BookmarkNode*> nodes; 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetBookmarkModel(profile)->GetNodesByURL(url, &nodes); 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(1U, nodes.size()); 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nodes.empty()) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return nodes[0]; 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CountBookmarksWithTitlesMatching(int profile, const std::wstring& title) { 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CountNodesWithTitlesMatching(GetBookmarkModel(profile), 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::URL, 7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WideToUTF16(title)); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CountFoldersWithTitlesMatching(int profile, const std::wstring& title) { 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CountNodesWithTitlesMatching(GetBookmarkModel(profile), 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BookmarkNode::FOLDER, 7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WideToUTF16(title)); 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Image CreateFavicon(SkColor color) { 7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int dip_width = 16; 7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int dip_height = 16; 7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<ui::ScaleFactor> favicon_scale_factors = 7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FaviconUtil::GetFaviconScaleFactors(); 7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::ImageSkia favicon; 7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (size_t i = 0; i < favicon_scale_factors.size(); ++i) { 76068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) float scale = ui::GetImageScale(favicon_scale_factors[i]); 7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int pixel_width = dip_width * scale; 7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int pixel_height = dip_height * scale; 7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkBitmap bmp; 7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bmp.setConfig(SkBitmap::kARGB_8888_Config, pixel_width, pixel_height); 7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bmp.allocPixels(); 7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bmp.eraseColor(color); 76768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) favicon.AddRepresentation( 76868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) gfx::ImageSkiaRep(bmp, 76968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ui::GetImageScale(favicon_scale_factors[i]))); 7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Image(favicon); 7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Image Create1xFaviconFromPNGFile(const std::string& path) { 7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const char* kPNGExtension = ".png"; 7762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!EndsWith(path, kPNGExtension, false)) 7772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Image(); 7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath full_path; 7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!PathService::Get(chrome::DIR_TEST_DATA, &full_path)) 7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Image(); 7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) full_path = full_path.AppendASCII("sync").AppendASCII(path); 7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string contents; 78558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::ReadFileToString(full_path, &contents); 7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Image::CreateFrom1xPNGBytes( 7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::RefCountedString::TakeString(&contents)); 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string IndexedURL(int i) { 7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::StringPrintf("http://www.host.ext:1234/path/filename/%d", i); 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring IndexedURLTitle(int i) { 7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::StringPrintf(L"URL Title %d", i); 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring IndexedFolderName(int i) { 7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::StringPrintf(L"Folder Name %d", i); 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring IndexedSubfolderName(int i) { 8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::StringPrintf(L"Subfolder Name %d", i); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring IndexedSubsubfolderName(int i) { 8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::StringPrintf(L"Subsubfolder Name %d", i); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace bookmarks_helper 811