1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/bookmarks/chrome_bookmark_client.h" 6 7#include "base/macros.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/strings/utf_string_conversions.h" 10#include "base/values.h" 11#include "chrome/browser/bookmarks/bookmark_model_factory.h" 12#include "chrome/browser/bookmarks/chrome_bookmark_client.h" 13#include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h" 14#include "chrome/test/base/testing_pref_service_syncable.h" 15#include "chrome/test/base/testing_profile.h" 16#include "components/bookmarks/browser/bookmark_model.h" 17#include "components/bookmarks/browser/bookmark_node.h" 18#include "components/bookmarks/common/bookmark_pref_names.h" 19#include "components/bookmarks/test/bookmark_test_helpers.h" 20#include "components/bookmarks/test/mock_bookmark_model_observer.h" 21#include "content/public/test/test_browser_thread_bundle.h" 22#include "grit/components_strings.h" 23#include "testing/gmock/include/gmock/gmock.h" 24#include "testing/gtest/include/gtest/gtest.h" 25#include "ui/base/l10n/l10n_util.h" 26 27using testing::Mock; 28using testing::_; 29 30class ChromeBookmarkClientTest : public testing::Test { 31 public: 32 ChromeBookmarkClientTest() : client_(NULL), model_(NULL) {} 33 virtual ~ChromeBookmarkClientTest() {} 34 35 virtual void SetUp() OVERRIDE { 36 prefs_ = profile_.GetTestingPrefService(); 37 ASSERT_FALSE(prefs_->HasPrefPath(bookmarks::prefs::kManagedBookmarks)); 38 39 prefs_->SetManagedPref(bookmarks::prefs::kManagedBookmarks, 40 CreateTestTree()); 41 ResetModel(); 42 43 // The managed node always exists. 44 ASSERT_TRUE(client_->managed_node()); 45 ASSERT_TRUE(client_->managed_node()->parent() == model_->root_node()); 46 EXPECT_NE(-1, model_->root_node()->GetIndexOf(client_->managed_node())); 47 } 48 49 virtual void TearDown() OVERRIDE { 50 model_->RemoveObserver(&observer_); 51 } 52 53 void ResetModel() { 54 profile_.CreateBookmarkModel(false); 55 model_ = BookmarkModelFactory::GetForProfile(&profile_); 56 test::WaitForBookmarkModelToLoad(model_); 57 model_->AddObserver(&observer_); 58 client_ = ChromeBookmarkClientFactory::GetForProfile(&profile_); 59 DCHECK(client_); 60 } 61 62 static base::DictionaryValue* CreateBookmark(const std::string& title, 63 const std::string& url) { 64 EXPECT_TRUE(GURL(url).is_valid()); 65 base::DictionaryValue* dict = new base::DictionaryValue(); 66 dict->SetString("name", title); 67 dict->SetString("url", GURL(url).spec()); 68 return dict; 69 } 70 71 static base::DictionaryValue* CreateFolder(const std::string& title, 72 base::ListValue* children) { 73 base::DictionaryValue* dict = new base::DictionaryValue(); 74 dict->SetString("name", title); 75 dict->Set("children", children); 76 return dict; 77 } 78 79 static base::ListValue* CreateTestTree() { 80 base::ListValue* folder = new base::ListValue(); 81 base::ListValue* empty = new base::ListValue(); 82 folder->Append(CreateFolder("Empty", empty)); 83 folder->Append(CreateBookmark("Youtube", "http://youtube.com/")); 84 85 base::ListValue* list = new base::ListValue(); 86 list->Append(CreateBookmark("Google", "http://google.com/")); 87 list->Append(CreateFolder("Folder", folder)); 88 89 return list; 90 } 91 92 static base::DictionaryValue* CreateExpectedTree() { 93 return CreateFolder(GetManagedFolderTitle(), CreateTestTree()); 94 } 95 96 static std::string GetManagedFolderTitle() { 97 return l10n_util::GetStringUTF8( 98 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME); 99 } 100 101 static bool NodeMatchesValue(const BookmarkNode* node, 102 const base::DictionaryValue* dict) { 103 base::string16 title; 104 if (!dict->GetString("name", &title) || node->GetTitle() != title) 105 return false; 106 107 if (node->is_folder()) { 108 const base::ListValue* children = NULL; 109 if (!dict->GetList("children", &children) || 110 node->child_count() != static_cast<int>(children->GetSize())) { 111 return false; 112 } 113 for (int i = 0; i < node->child_count(); ++i) { 114 const base::DictionaryValue* child = NULL; 115 if (!children->GetDictionary(i, &child) || 116 !NodeMatchesValue(node->GetChild(i), child)) { 117 return false; 118 } 119 } 120 } else if (node->is_url()) { 121 std::string url; 122 if (!dict->GetString("url", &url) || node->url() != GURL(url)) 123 return false; 124 } else { 125 return false; 126 } 127 return true; 128 } 129 130 content::TestBrowserThreadBundle thread_bundle_; 131 TestingProfile profile_; 132 TestingPrefServiceSyncable* prefs_; 133 bookmarks::MockBookmarkModelObserver observer_; 134 ChromeBookmarkClient* client_; 135 BookmarkModel* model_; 136 137 DISALLOW_COPY_AND_ASSIGN(ChromeBookmarkClientTest); 138}; 139 140TEST_F(ChromeBookmarkClientTest, EmptyManagedNode) { 141 // Verifies that the managed node is empty and invisible when the policy is 142 // not set. 143 model_->RemoveObserver(&observer_); 144 prefs_->RemoveManagedPref(bookmarks::prefs::kManagedBookmarks); 145 ResetModel(); 146 147 ASSERT_TRUE(client_->managed_node()); 148 EXPECT_TRUE(client_->managed_node()->empty()); 149 EXPECT_FALSE(client_->managed_node()->IsVisible()); 150} 151 152TEST_F(ChromeBookmarkClientTest, LoadInitial) { 153 // Verifies that the initial load picks up the initial policy too. 154 EXPECT_TRUE(model_->bookmark_bar_node()->empty()); 155 EXPECT_TRUE(model_->other_node()->empty()); 156 EXPECT_FALSE(client_->managed_node()->empty()); 157 EXPECT_TRUE(client_->managed_node()->IsVisible()); 158 159 scoped_ptr<base::DictionaryValue> expected(CreateExpectedTree()); 160 EXPECT_TRUE(NodeMatchesValue(client_->managed_node(), expected.get())); 161} 162 163TEST_F(ChromeBookmarkClientTest, SwapNodes) { 164 // Swap the Google bookmark with the Folder. 165 scoped_ptr<base::ListValue> updated(CreateTestTree()); 166 scoped_ptr<base::Value> removed; 167 ASSERT_TRUE(updated->Remove(0, &removed)); 168 updated->Append(removed.release()); 169 170 // These two nodes should just be swapped. 171 const BookmarkNode* parent = client_->managed_node(); 172 EXPECT_CALL(observer_, BookmarkNodeMoved(model_, parent, 1, parent, 0)); 173 prefs_->SetManagedPref(bookmarks::prefs::kManagedBookmarks, 174 updated->DeepCopy()); 175 Mock::VerifyAndClearExpectations(&observer_); 176 177 // Verify the final tree. 178 scoped_ptr<base::DictionaryValue> expected( 179 CreateFolder(GetManagedFolderTitle(), updated.release())); 180 EXPECT_TRUE(NodeMatchesValue(client_->managed_node(), expected.get())); 181} 182 183TEST_F(ChromeBookmarkClientTest, RemoveNode) { 184 // Remove the Folder. 185 scoped_ptr<base::ListValue> updated(CreateTestTree()); 186 ASSERT_TRUE(updated->Remove(1, NULL)); 187 188 const BookmarkNode* parent = client_->managed_node(); 189 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_, parent, 1, _, _)); 190 prefs_->SetManagedPref(bookmarks::prefs::kManagedBookmarks, 191 updated->DeepCopy()); 192 Mock::VerifyAndClearExpectations(&observer_); 193 194 // Verify the final tree. 195 scoped_ptr<base::DictionaryValue> expected( 196 CreateFolder(GetManagedFolderTitle(), updated.release())); 197 EXPECT_TRUE(NodeMatchesValue(client_->managed_node(), expected.get())); 198} 199 200TEST_F(ChromeBookmarkClientTest, CreateNewNodes) { 201 // Put all the nodes inside another folder. 202 scoped_ptr<base::ListValue> updated(new base::ListValue); 203 updated->Append(CreateFolder("Container", CreateTestTree())); 204 205 EXPECT_CALL(observer_, BookmarkNodeAdded(model_, _, _)).Times(5); 206 // The remaining nodes have been pushed to positions 1 and 2; they'll both be 207 // removed when at position 1. 208 const BookmarkNode* parent = client_->managed_node(); 209 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_, parent, 1, _, _)) 210 .Times(2); 211 prefs_->SetManagedPref(bookmarks::prefs::kManagedBookmarks, 212 updated->DeepCopy()); 213 Mock::VerifyAndClearExpectations(&observer_); 214 215 // Verify the final tree. 216 scoped_ptr<base::DictionaryValue> expected( 217 CreateFolder(GetManagedFolderTitle(), updated.release())); 218 EXPECT_TRUE(NodeMatchesValue(client_->managed_node(), expected.get())); 219} 220 221TEST_F(ChromeBookmarkClientTest, RemoveAllUserBookmarks) { 222 // Remove the policy. 223 const BookmarkNode* parent = client_->managed_node(); 224 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_, parent, 0, _, _)) 225 .Times(2); 226 prefs_->RemoveManagedPref(bookmarks::prefs::kManagedBookmarks); 227 Mock::VerifyAndClearExpectations(&observer_); 228 229 EXPECT_TRUE(client_->managed_node()->empty()); 230 EXPECT_FALSE(client_->managed_node()->IsVisible()); 231} 232 233TEST_F(ChromeBookmarkClientTest, IsDescendantOfManagedNode) { 234 EXPECT_FALSE(client_->IsDescendantOfManagedNode(model_->root_node())); 235 EXPECT_FALSE(client_->IsDescendantOfManagedNode(model_->bookmark_bar_node())); 236 EXPECT_FALSE(client_->IsDescendantOfManagedNode(model_->other_node())); 237 EXPECT_FALSE(client_->IsDescendantOfManagedNode(model_->mobile_node())); 238 EXPECT_TRUE(client_->IsDescendantOfManagedNode(client_->managed_node())); 239 240 const BookmarkNode* parent = client_->managed_node(); 241 ASSERT_EQ(2, parent->child_count()); 242 EXPECT_TRUE(client_->IsDescendantOfManagedNode(parent->GetChild(0))); 243 EXPECT_TRUE(client_->IsDescendantOfManagedNode(parent->GetChild(1))); 244 245 parent = parent->GetChild(1); 246 ASSERT_EQ(2, parent->child_count()); 247 EXPECT_TRUE(client_->IsDescendantOfManagedNode(parent->GetChild(0))); 248 EXPECT_TRUE(client_->IsDescendantOfManagedNode(parent->GetChild(1))); 249} 250 251TEST_F(ChromeBookmarkClientTest, RemoveAllDoesntRemoveManaged) { 252 EXPECT_EQ(2, client_->managed_node()->child_count()); 253 254 EXPECT_CALL(observer_, 255 BookmarkNodeAdded(model_, model_->bookmark_bar_node(), 0)); 256 EXPECT_CALL(observer_, 257 BookmarkNodeAdded(model_, model_->bookmark_bar_node(), 1)); 258 model_->AddURL(model_->bookmark_bar_node(), 259 0, 260 base::ASCIIToUTF16("Test"), 261 GURL("http://google.com/")); 262 model_->AddFolder( 263 model_->bookmark_bar_node(), 1, base::ASCIIToUTF16("Test Folder")); 264 EXPECT_EQ(2, model_->bookmark_bar_node()->child_count()); 265 Mock::VerifyAndClearExpectations(&observer_); 266 267 EXPECT_CALL(observer_, BookmarkAllUserNodesRemoved(model_, _)); 268 model_->RemoveAllUserBookmarks(); 269 EXPECT_EQ(2, client_->managed_node()->child_count()); 270 EXPECT_EQ(0, model_->bookmark_bar_node()->child_count()); 271 Mock::VerifyAndClearExpectations(&observer_); 272} 273 274TEST_F(ChromeBookmarkClientTest, HasDescendantsOfManagedNode) { 275 const BookmarkNode* user_node = model_->AddURL(model_->other_node(), 276 0, 277 base::ASCIIToUTF16("foo bar"), 278 GURL("http://www.google.com")); 279 const BookmarkNode* managed_node = client_->managed_node()->GetChild(0); 280 ASSERT_TRUE(managed_node); 281 282 std::vector<const BookmarkNode*> nodes; 283 EXPECT_FALSE(client_->HasDescendantsOfManagedNode(nodes)); 284 nodes.push_back(user_node); 285 EXPECT_FALSE(client_->HasDescendantsOfManagedNode(nodes)); 286 nodes.push_back(managed_node); 287 EXPECT_TRUE(client_->HasDescendantsOfManagedNode(nodes)); 288} 289