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 "components/policy/core/browser/managed_bookmarks_tracker.h"
6
7 #include "base/bind.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/bookmarks/browser/bookmark_model.h"
15 #include "components/bookmarks/browser/bookmark_model_observer.h"
16 #include "components/bookmarks/browser/bookmark_node.h"
17 #include "components/bookmarks/common/bookmark_pref_names.h"
18 #include "components/bookmarks/test/bookmark_test_helpers.h"
19 #include "components/bookmarks/test/mock_bookmark_model_observer.h"
20 #include "components/bookmarks/test/test_bookmark_client.h"
21 #include "grit/components_strings.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "url/gurl.h"
26
27 using testing::Mock;
28 using testing::_;
29
30 namespace policy {
31
32 class ManagedBookmarksTrackerTest : public testing::Test {
33 public:
ManagedBookmarksTrackerTest()34 ManagedBookmarksTrackerTest() : managed_node_(NULL) {}
~ManagedBookmarksTrackerTest()35 virtual ~ManagedBookmarksTrackerTest() {}
36
SetUp()37 virtual void SetUp() OVERRIDE {
38 prefs_.registry()->RegisterListPref(prefs::kManagedBookmarks);
39 prefs_.registry()->RegisterListPref(prefs::kBookmarkEditorExpandedNodes);
40 }
41
TearDown()42 virtual void TearDown() OVERRIDE {
43 if (model_)
44 model_->RemoveObserver(&observer_);
45 }
46
CreateModel()47 void CreateModel() {
48 // Simulate the creation of the managed node by the BookmarkClient.
49 BookmarkPermanentNode* managed_node = new BookmarkPermanentNode(100);
50 policy::ManagedBookmarksTracker::LoadInitial(
51 managed_node, prefs_.GetList(prefs::kManagedBookmarks), 101);
52 managed_node->set_visible(!managed_node->empty());
53 managed_node->SetTitle(l10n_util::GetStringUTF16(
54 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME));
55
56 bookmarks::BookmarkPermanentNodeList extra_nodes;
57 extra_nodes.push_back(managed_node);
58 client_.SetExtraNodesToLoad(extra_nodes.Pass());
59
60 model_.reset(new BookmarkModel(&client_, false));
61 model_->AddObserver(&observer_);
62 EXPECT_CALL(observer_, BookmarkModelLoaded(model_.get(), _));
63 model_->Load(&prefs_,
64 std::string(),
65 base::FilePath(),
66 base::MessageLoopProxy::current(),
67 base::MessageLoopProxy::current());
68 test::WaitForBookmarkModelToLoad(model_.get());
69 Mock::VerifyAndClearExpectations(&observer_);
70
71 ASSERT_EQ(1u, client_.extra_nodes().size());
72 managed_node_ = client_.extra_nodes()[0];
73 ASSERT_EQ(managed_node, managed_node_);
74
75 managed_bookmarks_tracker_.reset(new ManagedBookmarksTracker(
76 model_.get(),
77 &prefs_,
78 base::Bind(&ManagedBookmarksTrackerTest::GetManagementDomain)));
79 managed_bookmarks_tracker_->Init(managed_node_);
80 }
81
managed_node()82 const BookmarkNode* managed_node() {
83 return managed_node_;
84 }
85
IsManaged(const BookmarkNode * node)86 bool IsManaged(const BookmarkNode* node) {
87 return node && node->HasAncestor(managed_node_);
88 }
89
CreateBookmark(const std::string & title,const std::string & url)90 static base::DictionaryValue* CreateBookmark(const std::string& title,
91 const std::string& url) {
92 EXPECT_TRUE(GURL(url).is_valid());
93 base::DictionaryValue* dict = new base::DictionaryValue();
94 dict->SetString("name", title);
95 dict->SetString("url", GURL(url).spec());
96 return dict;
97 }
98
CreateFolder(const std::string & title,base::ListValue * children)99 static base::DictionaryValue* CreateFolder(const std::string& title,
100 base::ListValue* children) {
101 base::DictionaryValue* dict = new base::DictionaryValue();
102 dict->SetString("name", title);
103 dict->Set("children", children);
104 return dict;
105 }
106
CreateTestTree()107 static base::ListValue* CreateTestTree() {
108 base::ListValue* folder = new base::ListValue();
109 base::ListValue* empty = new base::ListValue();
110 folder->Append(CreateFolder("Empty", empty));
111 folder->Append(CreateBookmark("Youtube", "http://youtube.com/"));
112
113 base::ListValue* list = new base::ListValue();
114 list->Append(CreateBookmark("Google", "http://google.com/"));
115 list->Append(CreateFolder("Folder", folder));
116
117 return list;
118 }
119
GetManagementDomain()120 static std::string GetManagementDomain() {
121 return std::string();
122 }
123
GetManagedFolderTitle()124 static std::string GetManagedFolderTitle() {
125 return l10n_util::GetStringUTF8(
126 IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME);
127 }
128
CreateExpectedTree()129 static base::DictionaryValue* CreateExpectedTree() {
130 return CreateFolder(GetManagedFolderTitle(), CreateTestTree());
131 }
132
NodeMatchesValue(const BookmarkNode * node,const base::DictionaryValue * dict)133 static bool NodeMatchesValue(const BookmarkNode* node,
134 const base::DictionaryValue* dict) {
135 base::string16 title;
136 if (!dict->GetString("name", &title) || node->GetTitle() != title)
137 return false;
138
139 if (node->is_folder()) {
140 const base::ListValue* children = NULL;
141 if (!dict->GetList("children", &children) ||
142 node->child_count() != static_cast<int>(children->GetSize())) {
143 return false;
144 }
145 for (int i = 0; i < node->child_count(); ++i) {
146 const base::DictionaryValue* child = NULL;
147 if (!children->GetDictionary(i, &child) ||
148 !NodeMatchesValue(node->GetChild(i), child)) {
149 return false;
150 }
151 }
152 } else if (node->is_url()) {
153 std::string url;
154 if (!dict->GetString("url", &url) || node->url() != GURL(url))
155 return false;
156 } else {
157 return false;
158 }
159 return true;
160 }
161
162 base::MessageLoop loop_;
163 TestingPrefServiceSimple prefs_;
164 test::TestBookmarkClient client_;
165 scoped_ptr<BookmarkModel> model_;
166 MockBookmarkModelObserver observer_;
167 BookmarkPermanentNode* managed_node_;
168 scoped_ptr<ManagedBookmarksTracker> managed_bookmarks_tracker_;
169 };
170
TEST_F(ManagedBookmarksTrackerTest,Empty)171 TEST_F(ManagedBookmarksTrackerTest, Empty) {
172 CreateModel();
173 EXPECT_TRUE(model_->bookmark_bar_node()->empty());
174 EXPECT_TRUE(model_->other_node()->empty());
175 EXPECT_TRUE(managed_node()->empty());
176 EXPECT_FALSE(managed_node()->IsVisible());
177 }
178
TEST_F(ManagedBookmarksTrackerTest,LoadInitial)179 TEST_F(ManagedBookmarksTrackerTest, LoadInitial) {
180 // Set a policy before loading the model.
181 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
182 CreateModel();
183 EXPECT_TRUE(model_->bookmark_bar_node()->empty());
184 EXPECT_TRUE(model_->other_node()->empty());
185 EXPECT_FALSE(managed_node()->empty());
186 EXPECT_TRUE(managed_node()->IsVisible());
187
188 scoped_ptr<base::DictionaryValue> expected(CreateExpectedTree());
189 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
190 }
191
TEST_F(ManagedBookmarksTrackerTest,SwapNodes)192 TEST_F(ManagedBookmarksTrackerTest, SwapNodes) {
193 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
194 CreateModel();
195
196 // Swap the Google bookmark with the Folder.
197 scoped_ptr<base::ListValue> updated(CreateTestTree());
198 scoped_ptr<base::Value> removed;
199 ASSERT_TRUE(updated->Remove(0, &removed));
200 updated->Append(removed.release());
201
202 // These two nodes should just be swapped.
203 const BookmarkNode* parent = managed_node();
204 EXPECT_CALL(observer_, BookmarkNodeMoved(model_.get(), parent, 1, parent, 0));
205 prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
206 Mock::VerifyAndClearExpectations(&observer_);
207
208 // Verify the final tree.
209 scoped_ptr<base::DictionaryValue> expected(
210 CreateFolder(GetManagedFolderTitle(), updated.release()));
211 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
212 }
213
TEST_F(ManagedBookmarksTrackerTest,RemoveNode)214 TEST_F(ManagedBookmarksTrackerTest, RemoveNode) {
215 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
216 CreateModel();
217
218 // Remove the Folder.
219 scoped_ptr<base::ListValue> updated(CreateTestTree());
220 ASSERT_TRUE(updated->Remove(1, NULL));
221
222 const BookmarkNode* parent = managed_node();
223 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _));
224 prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
225 Mock::VerifyAndClearExpectations(&observer_);
226
227 // Verify the final tree.
228 scoped_ptr<base::DictionaryValue> expected(
229 CreateFolder(GetManagedFolderTitle(), updated.release()));
230 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
231 }
232
TEST_F(ManagedBookmarksTrackerTest,CreateNewNodes)233 TEST_F(ManagedBookmarksTrackerTest, CreateNewNodes) {
234 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
235 CreateModel();
236
237 // Put all the nodes inside another folder.
238 scoped_ptr<base::ListValue> updated(new base::ListValue);
239 updated->Append(CreateFolder("Container", CreateTestTree()));
240
241 EXPECT_CALL(observer_, BookmarkNodeAdded(model_.get(), _, _)).Times(5);
242 // The remaining nodes have been pushed to positions 1 and 2; they'll both be
243 // removed when at position 1.
244 const BookmarkNode* parent = managed_node();
245 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 1, _, _))
246 .Times(2);
247 prefs_.SetManagedPref(prefs::kManagedBookmarks, updated->DeepCopy());
248 Mock::VerifyAndClearExpectations(&observer_);
249
250 // Verify the final tree.
251 scoped_ptr<base::DictionaryValue> expected(
252 CreateFolder(GetManagedFolderTitle(), updated.release()));
253 EXPECT_TRUE(NodeMatchesValue(managed_node(), expected.get()));
254 }
255
TEST_F(ManagedBookmarksTrackerTest,RemoveAll)256 TEST_F(ManagedBookmarksTrackerTest, RemoveAll) {
257 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
258 CreateModel();
259 EXPECT_TRUE(managed_node()->IsVisible());
260
261 // Remove the policy.
262 const BookmarkNode* parent = managed_node();
263 EXPECT_CALL(observer_, BookmarkNodeRemoved(model_.get(), parent, 0, _, _))
264 .Times(2);
265 prefs_.RemoveManagedPref(prefs::kManagedBookmarks);
266 Mock::VerifyAndClearExpectations(&observer_);
267
268 EXPECT_TRUE(managed_node()->empty());
269 EXPECT_FALSE(managed_node()->IsVisible());
270 }
271
TEST_F(ManagedBookmarksTrackerTest,IsManaged)272 TEST_F(ManagedBookmarksTrackerTest, IsManaged) {
273 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
274 CreateModel();
275
276 EXPECT_FALSE(IsManaged(model_->root_node()));
277 EXPECT_FALSE(IsManaged(model_->bookmark_bar_node()));
278 EXPECT_FALSE(IsManaged(model_->other_node()));
279 EXPECT_FALSE(IsManaged(model_->mobile_node()));
280 EXPECT_TRUE(IsManaged(managed_node()));
281
282 const BookmarkNode* parent = managed_node();
283 ASSERT_EQ(2, parent->child_count());
284 EXPECT_TRUE(IsManaged(parent->GetChild(0)));
285 EXPECT_TRUE(IsManaged(parent->GetChild(1)));
286
287 parent = parent->GetChild(1);
288 ASSERT_EQ(2, parent->child_count());
289 EXPECT_TRUE(IsManaged(parent->GetChild(0)));
290 EXPECT_TRUE(IsManaged(parent->GetChild(1)));
291 }
292
TEST_F(ManagedBookmarksTrackerTest,RemoveAllUserBookmarksDoesntRemoveManaged)293 TEST_F(ManagedBookmarksTrackerTest, RemoveAllUserBookmarksDoesntRemoveManaged) {
294 prefs_.SetManagedPref(prefs::kManagedBookmarks, CreateTestTree());
295 CreateModel();
296 EXPECT_EQ(2, managed_node()->child_count());
297
298 EXPECT_CALL(observer_,
299 BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 0));
300 EXPECT_CALL(observer_,
301 BookmarkNodeAdded(model_.get(), model_->bookmark_bar_node(), 1));
302 model_->AddURL(model_->bookmark_bar_node(),
303 0,
304 base::ASCIIToUTF16("Test"),
305 GURL("http://google.com/"));
306 model_->AddFolder(
307 model_->bookmark_bar_node(), 1, base::ASCIIToUTF16("Test Folder"));
308 EXPECT_EQ(2, model_->bookmark_bar_node()->child_count());
309 Mock::VerifyAndClearExpectations(&observer_);
310
311 EXPECT_CALL(observer_, BookmarkAllUserNodesRemoved(model_.get(), _));
312 model_->RemoveAllUserBookmarks();
313 EXPECT_EQ(2, managed_node()->child_count());
314 EXPECT_EQ(0, model_->bookmark_bar_node()->child_count());
315 Mock::VerifyAndClearExpectations(&observer_);
316 }
317
318 } // namespace policy
319