OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/bookmarks/core/browser/bookmark_model.h" | |
6 | |
7 #include <set> | |
8 #include <string> | |
9 | |
10 #include "base/base_paths.h" | |
11 #include "base/basictypes.h" | |
12 #include "base/command_line.h" | |
13 #include "base/compiler_specific.h" | |
14 #include "base/containers/hash_tables.h" | |
15 #include "base/path_service.h" | |
16 #include "base/strings/string16.h" | |
17 #include "base/strings/string_number_conversions.h" | |
18 #include "base/strings/string_split.h" | |
19 #include "base/strings/string_util.h" | |
20 #include "base/strings/utf_string_conversions.h" | |
21 #include "base/time/time.h" | |
22 #include "components/bookmarks/core/browser/bookmark_model_observer.h" | |
23 #include "components/bookmarks/core/browser/bookmark_utils.h" | |
24 #include "components/bookmarks/core/test/bookmark_test_helpers.h" | |
25 #include "components/bookmarks/core/test/test_bookmark_client.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 #include "ui/base/models/tree_node_iterator.h" | |
28 #include "ui/base/models/tree_node_model.h" | |
29 #include "url/gurl.h" | |
30 | |
31 using base::ASCIIToUTF16; | |
32 using base::Time; | |
33 using base::TimeDelta; | |
34 | |
35 namespace { | |
36 | |
37 // Test cases used to test the removal of extra whitespace when adding | |
38 // a new folder/bookmark or updating a title of a folder/bookmark. | |
39 static struct { | |
40 const std::string input_title; | |
41 const std::string expected_title; | |
42 } url_whitespace_test_cases[] = { | |
43 {"foobar", "foobar"}, | |
44 // Newlines. | |
45 {"foo\nbar", "foo bar"}, | |
46 {"foo\n\nbar", "foo bar"}, | |
47 {"foo\n\n\nbar", "foo bar"}, | |
48 {"foo\r\nbar", "foo bar"}, | |
49 {"foo\r\n\r\nbar", "foo bar"}, | |
50 {"\nfoo\nbar\n", "foo bar"}, | |
51 // Spaces. | |
52 {"foo bar", "foo bar"}, | |
53 {" foo bar ", "foo bar"}, | |
54 {" foo bar ", "foo bar"}, | |
55 // Tabs. | |
56 {"\tfoo\tbar\t", "foo bar"}, | |
57 {"\tfoo bar\t", "foo bar"}, | |
58 // Mixed cases. | |
59 {"\tfoo\nbar\t", "foo bar"}, | |
60 {"\tfoo\r\nbar\t", "foo bar"}, | |
61 {" foo\tbar\n", "foo bar"}, | |
62 {"\t foo \t bar \t", "foo bar"}, | |
63 {"\n foo\r\n\tbar\n \t", "foo bar"}, | |
64 }; | |
65 | |
66 // Test cases used to test the removal of extra whitespace when adding | |
67 // a new folder/bookmark or updating a title of a folder/bookmark. | |
68 static struct { | |
69 const std::string input_title; | |
70 const std::string expected_title; | |
71 } title_whitespace_test_cases[] = { | |
72 {"foobar", "foobar"}, | |
73 // Newlines. | |
74 {"foo\nbar", "foo bar"}, | |
75 {"foo\n\nbar", "foo bar"}, | |
76 {"foo\n\n\nbar", "foo bar"}, | |
77 {"foo\r\nbar", "foo bar"}, | |
78 {"foo\r\n\r\nbar", "foo bar"}, | |
79 {"\nfoo\nbar\n", " foo bar "}, | |
80 // Spaces. | |
81 {"foo bar", "foo bar"}, | |
82 {" foo bar ", " foo bar "}, | |
83 {" foo bar ", " foo bar "}, | |
84 // Tabs. | |
85 {"\tfoo\tbar\t", " foo bar "}, | |
86 {"\tfoo bar\t", " foo bar "}, | |
87 // Mixed cases. | |
88 {"\tfoo\nbar\t", " foo bar "}, | |
89 {"\tfoo\r\nbar\t", " foo bar "}, | |
90 {" foo\tbar\n", " foo bar "}, | |
91 {"\t foo \t bar \t", " foo bar "}, | |
92 {"\n foo\r\n\tbar\n \t", " foo bar "}, | |
93 }; | |
94 | |
95 // Helper to get a mutable bookmark node. | |
96 BookmarkNode* AsMutable(const BookmarkNode* node) { | |
97 return const_cast<BookmarkNode*>(node); | |
98 } | |
99 | |
100 void SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) { | |
101 Time tmp = n1->date_added(); | |
102 n1->set_date_added(n2->date_added()); | |
103 n2->set_date_added(tmp); | |
104 } | |
105 | |
106 class BookmarkModelTest : public testing::Test, | |
107 public BookmarkModelObserver { | |
108 public: | |
109 struct ObserverDetails { | |
110 ObserverDetails() { | |
111 Set(NULL, NULL, -1, -1); | |
112 } | |
113 | |
114 void Set(const BookmarkNode* node1, | |
115 const BookmarkNode* node2, | |
116 int index1, | |
117 int index2) { | |
118 node1_ = node1; | |
119 node2_ = node2; | |
120 index1_ = index1; | |
121 index2_ = index2; | |
122 } | |
123 | |
124 void ExpectEquals(const BookmarkNode* node1, | |
125 const BookmarkNode* node2, | |
126 int index1, | |
127 int index2) { | |
128 EXPECT_EQ(node1_, node1); | |
129 EXPECT_EQ(node2_, node2); | |
130 EXPECT_EQ(index1_, index1); | |
131 EXPECT_EQ(index2_, index2); | |
132 } | |
133 | |
134 private: | |
135 const BookmarkNode* node1_; | |
136 const BookmarkNode* node2_; | |
137 int index1_; | |
138 int index2_; | |
139 }; | |
140 | |
141 BookmarkModelTest() : model_(client_.CreateModel(false)) { | |
142 model_->AddObserver(this); | |
143 ClearCounts(); | |
144 } | |
145 | |
146 virtual void BookmarkModelLoaded(BookmarkModel* model, | |
147 bool ids_reassigned) OVERRIDE { | |
148 // We never load from the db, so that this should never get invoked. | |
149 NOTREACHED(); | |
150 } | |
151 | |
152 virtual void BookmarkNodeMoved(BookmarkModel* model, | |
153 const BookmarkNode* old_parent, | |
154 int old_index, | |
155 const BookmarkNode* new_parent, | |
156 int new_index) OVERRIDE { | |
157 ++moved_count_; | |
158 observer_details_.Set(old_parent, new_parent, old_index, new_index); | |
159 } | |
160 | |
161 virtual void BookmarkNodeAdded(BookmarkModel* model, | |
162 const BookmarkNode* parent, | |
163 int index) OVERRIDE { | |
164 ++added_count_; | |
165 observer_details_.Set(parent, NULL, index, -1); | |
166 } | |
167 | |
168 virtual void OnWillRemoveBookmarks(BookmarkModel* model, | |
169 const BookmarkNode* parent, | |
170 int old_index, | |
171 const BookmarkNode* node) OVERRIDE { | |
172 ++before_remove_count_; | |
173 } | |
174 | |
175 virtual void BookmarkNodeRemoved( | |
176 BookmarkModel* model, | |
177 const BookmarkNode* parent, | |
178 int old_index, | |
179 const BookmarkNode* node, | |
180 const std::set<GURL>& removed_urls) OVERRIDE { | |
181 ++removed_count_; | |
182 observer_details_.Set(parent, NULL, old_index, -1); | |
183 } | |
184 | |
185 virtual void BookmarkNodeChanged(BookmarkModel* model, | |
186 const BookmarkNode* node) OVERRIDE { | |
187 ++changed_count_; | |
188 observer_details_.Set(node, NULL, -1, -1); | |
189 } | |
190 | |
191 virtual void OnWillChangeBookmarkNode(BookmarkModel* model, | |
192 const BookmarkNode* node) OVERRIDE { | |
193 ++before_change_count_; | |
194 } | |
195 | |
196 virtual void BookmarkNodeChildrenReordered( | |
197 BookmarkModel* model, | |
198 const BookmarkNode* node) OVERRIDE { | |
199 ++reordered_count_; | |
200 } | |
201 | |
202 virtual void OnWillReorderBookmarkNode(BookmarkModel* model, | |
203 const BookmarkNode* node) OVERRIDE { | |
204 ++before_reorder_count_; | |
205 } | |
206 | |
207 virtual void BookmarkNodeFaviconChanged(BookmarkModel* model, | |
208 const BookmarkNode* node) OVERRIDE { | |
209 // We never attempt to load favicons, so that this method never | |
210 // gets invoked. | |
211 } | |
212 | |
213 virtual void ExtensiveBookmarkChangesBeginning( | |
214 BookmarkModel* model) OVERRIDE { | |
215 ++extensive_changes_beginning_count_; | |
216 } | |
217 | |
218 virtual void ExtensiveBookmarkChangesEnded(BookmarkModel* model) OVERRIDE { | |
219 ++extensive_changes_ended_count_; | |
220 } | |
221 | |
222 virtual void BookmarkAllNodesRemoved( | |
223 BookmarkModel* model, | |
224 const std::set<GURL>& removed_urls) OVERRIDE { | |
225 ++all_bookmarks_removed_; | |
226 } | |
227 | |
228 virtual void OnWillRemoveAllBookmarks(BookmarkModel* model) OVERRIDE { | |
229 ++before_remove_all_count_; | |
230 } | |
231 | |
232 void ClearCounts() { | |
233 added_count_ = moved_count_ = removed_count_ = changed_count_ = | |
234 reordered_count_ = extensive_changes_beginning_count_ = | |
235 extensive_changes_ended_count_ = all_bookmarks_removed_ = | |
236 before_remove_count_ = before_change_count_ = before_reorder_count_ = | |
237 before_remove_all_count_ = 0; | |
238 } | |
239 | |
240 void AssertObserverCount(int added_count, | |
241 int moved_count, | |
242 int removed_count, | |
243 int changed_count, | |
244 int reordered_count, | |
245 int before_remove_count, | |
246 int before_change_count, | |
247 int before_reorder_count, | |
248 int before_remove_all_count) { | |
249 EXPECT_EQ(added_count_, added_count); | |
250 EXPECT_EQ(moved_count_, moved_count); | |
251 EXPECT_EQ(removed_count_, removed_count); | |
252 EXPECT_EQ(changed_count_, changed_count); | |
253 EXPECT_EQ(reordered_count_, reordered_count); | |
254 EXPECT_EQ(before_remove_count_, before_remove_count); | |
255 EXPECT_EQ(before_change_count_, before_change_count); | |
256 EXPECT_EQ(before_reorder_count_, before_reorder_count); | |
257 EXPECT_EQ(before_remove_all_count_, before_remove_all_count); | |
258 } | |
259 | |
260 void AssertExtensiveChangesObserverCount( | |
261 int extensive_changes_beginning_count, | |
262 int extensive_changes_ended_count) { | |
263 EXPECT_EQ(extensive_changes_beginning_count_, | |
264 extensive_changes_beginning_count); | |
265 EXPECT_EQ(extensive_changes_ended_count_, extensive_changes_ended_count); | |
266 } | |
267 | |
268 int AllNodesRemovedObserverCount() const { return all_bookmarks_removed_; } | |
269 | |
270 protected: | |
271 test::TestBookmarkClient client_; | |
272 scoped_ptr<BookmarkModel> model_; | |
273 ObserverDetails observer_details_; | |
274 | |
275 private: | |
276 int added_count_; | |
277 int moved_count_; | |
278 int removed_count_; | |
279 int changed_count_; | |
280 int reordered_count_; | |
281 int extensive_changes_beginning_count_; | |
282 int extensive_changes_ended_count_; | |
283 int all_bookmarks_removed_; | |
284 int before_remove_count_; | |
285 int before_change_count_; | |
286 int before_reorder_count_; | |
287 int before_remove_all_count_; | |
288 | |
289 DISALLOW_COPY_AND_ASSIGN(BookmarkModelTest); | |
290 }; | |
291 | |
292 TEST_F(BookmarkModelTest, InitialState) { | |
293 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
294 ASSERT_TRUE(bb_node != NULL); | |
295 EXPECT_EQ(0, bb_node->child_count()); | |
296 EXPECT_EQ(BookmarkNode::BOOKMARK_BAR, bb_node->type()); | |
297 | |
298 const BookmarkNode* other_node = model_->other_node(); | |
299 ASSERT_TRUE(other_node != NULL); | |
300 EXPECT_EQ(0, other_node->child_count()); | |
301 EXPECT_EQ(BookmarkNode::OTHER_NODE, other_node->type()); | |
302 | |
303 const BookmarkNode* mobile_node = model_->mobile_node(); | |
304 ASSERT_TRUE(mobile_node != NULL); | |
305 EXPECT_EQ(0, mobile_node->child_count()); | |
306 EXPECT_EQ(BookmarkNode::MOBILE, mobile_node->type()); | |
307 | |
308 EXPECT_TRUE(bb_node->id() != other_node->id()); | |
309 EXPECT_TRUE(bb_node->id() != mobile_node->id()); | |
310 EXPECT_TRUE(other_node->id() != mobile_node->id()); | |
311 } | |
312 | |
313 TEST_F(BookmarkModelTest, AddURL) { | |
314 const BookmarkNode* root = model_->bookmark_bar_node(); | |
315 const base::string16 title(ASCIIToUTF16("foo")); | |
316 const GURL url("http://foo.com"); | |
317 | |
318 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
319 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
320 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
321 | |
322 ASSERT_EQ(1, root->child_count()); | |
323 ASSERT_EQ(title, new_node->GetTitle()); | |
324 ASSERT_TRUE(url == new_node->url()); | |
325 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
326 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
327 | |
328 EXPECT_TRUE(new_node->id() != root->id() && | |
329 new_node->id() != model_->other_node()->id() && | |
330 new_node->id() != model_->mobile_node()->id()); | |
331 } | |
332 | |
333 TEST_F(BookmarkModelTest, AddURLWithUnicodeTitle) { | |
334 const BookmarkNode* root = model_->bookmark_bar_node(); | |
335 const base::string16 title(base::WideToUTF16( | |
336 L"\u767e\u5ea6\u4e00\u4e0b\uff0c\u4f60\u5c31\u77e5\u9053")); | |
337 const GURL url("https://www.baidu.com/"); | |
338 | |
339 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
340 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
341 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
342 | |
343 ASSERT_EQ(1, root->child_count()); | |
344 ASSERT_EQ(title, new_node->GetTitle()); | |
345 ASSERT_TRUE(url == new_node->url()); | |
346 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
347 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
348 | |
349 EXPECT_TRUE(new_node->id() != root->id() && | |
350 new_node->id() != model_->other_node()->id() && | |
351 new_node->id() != model_->mobile_node()->id()); | |
352 } | |
353 | |
354 TEST_F(BookmarkModelTest, AddURLWithWhitespaceTitle) { | |
355 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(url_whitespace_test_cases); ++i) { | |
356 const BookmarkNode* root = model_->bookmark_bar_node(); | |
357 const base::string16 title( | |
358 ASCIIToUTF16(url_whitespace_test_cases[i].input_title)); | |
359 const GURL url("http://foo.com"); | |
360 | |
361 const BookmarkNode* new_node = model_->AddURL(root, i, title, url); | |
362 | |
363 int size = i + 1; | |
364 EXPECT_EQ(size, root->child_count()); | |
365 EXPECT_EQ(ASCIIToUTF16(url_whitespace_test_cases[i].expected_title), | |
366 new_node->GetTitle()); | |
367 EXPECT_EQ(BookmarkNode::URL, new_node->type()); | |
368 } | |
369 } | |
370 | |
371 TEST_F(BookmarkModelTest, AddURLWithCreationTimeAndMetaInfo) { | |
372 const BookmarkNode* root = model_->bookmark_bar_node(); | |
373 const base::string16 title(ASCIIToUTF16("foo")); | |
374 const GURL url("http://foo.com"); | |
375 const Time time = Time::Now() - TimeDelta::FromDays(1); | |
376 BookmarkNode::MetaInfoMap meta_info; | |
377 meta_info["foo"] = "bar"; | |
378 | |
379 const BookmarkNode* new_node = model_->AddURLWithCreationTimeAndMetaInfo( | |
380 root, 0, title, url, time, &meta_info); | |
381 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
382 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
383 | |
384 ASSERT_EQ(1, root->child_count()); | |
385 ASSERT_EQ(title, new_node->GetTitle()); | |
386 ASSERT_TRUE(url == new_node->url()); | |
387 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
388 ASSERT_EQ(time, new_node->date_added()); | |
389 ASSERT_TRUE(new_node->GetMetaInfoMap()); | |
390 ASSERT_EQ(meta_info, *new_node->GetMetaInfoMap()); | |
391 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
392 | |
393 EXPECT_TRUE(new_node->id() != root->id() && | |
394 new_node->id() != model_->other_node()->id() && | |
395 new_node->id() != model_->mobile_node()->id()); | |
396 } | |
397 | |
398 TEST_F(BookmarkModelTest, AddURLToMobileBookmarks) { | |
399 const BookmarkNode* root = model_->mobile_node(); | |
400 const base::string16 title(ASCIIToUTF16("foo")); | |
401 const GURL url("http://foo.com"); | |
402 | |
403 const BookmarkNode* new_node = model_->AddURL(root, 0, title, url); | |
404 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
405 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
406 | |
407 ASSERT_EQ(1, root->child_count()); | |
408 ASSERT_EQ(title, new_node->GetTitle()); | |
409 ASSERT_TRUE(url == new_node->url()); | |
410 ASSERT_EQ(BookmarkNode::URL, new_node->type()); | |
411 ASSERT_TRUE(new_node == model_->GetMostRecentlyAddedNodeForURL(url)); | |
412 | |
413 EXPECT_TRUE(new_node->id() != root->id() && | |
414 new_node->id() != model_->other_node()->id() && | |
415 new_node->id() != model_->mobile_node()->id()); | |
416 } | |
417 | |
418 TEST_F(BookmarkModelTest, AddFolder) { | |
419 const BookmarkNode* root = model_->bookmark_bar_node(); | |
420 const base::string16 title(ASCIIToUTF16("foo")); | |
421 | |
422 const BookmarkNode* new_node = model_->AddFolder(root, 0, title); | |
423 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
424 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
425 | |
426 ASSERT_EQ(1, root->child_count()); | |
427 ASSERT_EQ(title, new_node->GetTitle()); | |
428 ASSERT_EQ(BookmarkNode::FOLDER, new_node->type()); | |
429 | |
430 EXPECT_TRUE(new_node->id() != root->id() && | |
431 new_node->id() != model_->other_node()->id() && | |
432 new_node->id() != model_->mobile_node()->id()); | |
433 | |
434 // Add another folder, just to make sure folder_ids are incremented correctly. | |
435 ClearCounts(); | |
436 model_->AddFolder(root, 0, title); | |
437 AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0); | |
438 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
439 } | |
440 | |
441 TEST_F(BookmarkModelTest, AddFolderWithWhitespaceTitle) { | |
442 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(title_whitespace_test_cases); ++i) { | |
443 const BookmarkNode* root = model_->bookmark_bar_node(); | |
444 const base::string16 title( | |
445 ASCIIToUTF16(title_whitespace_test_cases[i].input_title)); | |
446 | |
447 const BookmarkNode* new_node = model_->AddFolder(root, i, title); | |
448 | |
449 int size = i + 1; | |
450 EXPECT_EQ(size, root->child_count()); | |
451 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title), | |
452 new_node->GetTitle()); | |
453 EXPECT_EQ(BookmarkNode::FOLDER, new_node->type()); | |
454 } | |
455 } | |
456 | |
457 TEST_F(BookmarkModelTest, RemoveURL) { | |
458 const BookmarkNode* root = model_->bookmark_bar_node(); | |
459 const base::string16 title(ASCIIToUTF16("foo")); | |
460 const GURL url("http://foo.com"); | |
461 model_->AddURL(root, 0, title, url); | |
462 ClearCounts(); | |
463 | |
464 model_->Remove(root, 0); | |
465 ASSERT_EQ(0, root->child_count()); | |
466 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
467 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
468 | |
469 // Make sure there is no mapping for the URL. | |
470 ASSERT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
471 } | |
472 | |
473 TEST_F(BookmarkModelTest, RemoveFolder) { | |
474 const BookmarkNode* root = model_->bookmark_bar_node(); | |
475 const BookmarkNode* folder = model_->AddFolder(root, 0, ASCIIToUTF16("foo")); | |
476 | |
477 ClearCounts(); | |
478 | |
479 // Add a URL as a child. | |
480 const base::string16 title(ASCIIToUTF16("foo")); | |
481 const GURL url("http://foo.com"); | |
482 model_->AddURL(folder, 0, title, url); | |
483 | |
484 ClearCounts(); | |
485 | |
486 // Now remove the folder. | |
487 model_->Remove(root, 0); | |
488 ASSERT_EQ(0, root->child_count()); | |
489 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
490 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
491 | |
492 // Make sure there is no mapping for the URL. | |
493 ASSERT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
494 } | |
495 | |
496 TEST_F(BookmarkModelTest, RemoveAll) { | |
497 const BookmarkNode* bookmark_bar_node = model_->bookmark_bar_node(); | |
498 | |
499 ClearCounts(); | |
500 | |
501 // Add a url to bookmark bar. | |
502 base::string16 title(ASCIIToUTF16("foo")); | |
503 GURL url("http://foo.com"); | |
504 model_->AddURL(bookmark_bar_node, 0, title, url); | |
505 | |
506 // Add a folder with child URL. | |
507 const BookmarkNode* folder = model_->AddFolder(bookmark_bar_node, 0, title); | |
508 model_->AddURL(folder, 0, title, url); | |
509 | |
510 AssertObserverCount(3, 0, 0, 0, 0, 0, 0, 0, 0); | |
511 ClearCounts(); | |
512 | |
513 model_->RemoveAll(); | |
514 | |
515 EXPECT_EQ(0, bookmark_bar_node->child_count()); | |
516 // No individual BookmarkNodeRemoved events are fired, so removed count | |
517 // should be 0. | |
518 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 1); | |
519 AssertExtensiveChangesObserverCount(1, 1); | |
520 EXPECT_EQ(1, AllNodesRemovedObserverCount()); | |
521 } | |
522 | |
523 TEST_F(BookmarkModelTest, SetTitle) { | |
524 const BookmarkNode* root = model_->bookmark_bar_node(); | |
525 base::string16 title(ASCIIToUTF16("foo")); | |
526 const GURL url("http://foo.com"); | |
527 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
528 | |
529 ClearCounts(); | |
530 | |
531 title = ASCIIToUTF16("foo2"); | |
532 model_->SetTitle(node, title); | |
533 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); | |
534 observer_details_.ExpectEquals(node, NULL, -1, -1); | |
535 EXPECT_EQ(title, node->GetTitle()); | |
536 } | |
537 | |
538 TEST_F(BookmarkModelTest, SetTitleWithWhitespace) { | |
539 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(title_whitespace_test_cases); ++i) { | |
540 const BookmarkNode* root = model_->bookmark_bar_node(); | |
541 base::string16 title(ASCIIToUTF16("dummy")); | |
542 const GURL url("http://foo.com"); | |
543 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
544 | |
545 title = ASCIIToUTF16(title_whitespace_test_cases[i].input_title); | |
546 model_->SetTitle(node, title); | |
547 EXPECT_EQ(ASCIIToUTF16(title_whitespace_test_cases[i].expected_title), | |
548 node->GetTitle()); | |
549 } | |
550 } | |
551 | |
552 TEST_F(BookmarkModelTest, SetURL) { | |
553 const BookmarkNode* root = model_->bookmark_bar_node(); | |
554 const base::string16 title(ASCIIToUTF16("foo")); | |
555 GURL url("http://foo.com"); | |
556 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
557 | |
558 ClearCounts(); | |
559 | |
560 url = GURL("http://foo2.com"); | |
561 model_->SetURL(node, url); | |
562 AssertObserverCount(0, 0, 0, 1, 0, 0, 1, 0, 0); | |
563 observer_details_.ExpectEquals(node, NULL, -1, -1); | |
564 EXPECT_EQ(url, node->url()); | |
565 } | |
566 | |
567 TEST_F(BookmarkModelTest, SetDateAdded) { | |
568 const BookmarkNode* root = model_->bookmark_bar_node(); | |
569 const base::string16 title(ASCIIToUTF16("foo")); | |
570 GURL url("http://foo.com"); | |
571 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
572 | |
573 ClearCounts(); | |
574 | |
575 base::Time new_time = base::Time::Now() + base::TimeDelta::FromMinutes(20); | |
576 model_->SetDateAdded(node, new_time); | |
577 AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 0, 0); | |
578 EXPECT_EQ(new_time, node->date_added()); | |
579 EXPECT_EQ(new_time, model_->bookmark_bar_node()->date_folder_modified()); | |
580 } | |
581 | |
582 TEST_F(BookmarkModelTest, Move) { | |
583 const BookmarkNode* root = model_->bookmark_bar_node(); | |
584 const base::string16 title(ASCIIToUTF16("foo")); | |
585 const GURL url("http://foo.com"); | |
586 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
587 const BookmarkNode* folder1 = model_->AddFolder(root, 0, ASCIIToUTF16("foo")); | |
588 ClearCounts(); | |
589 | |
590 model_->Move(node, folder1, 0); | |
591 | |
592 AssertObserverCount(0, 1, 0, 0, 0, 0, 0, 0, 0); | |
593 observer_details_.ExpectEquals(root, folder1, 1, 0); | |
594 EXPECT_TRUE(folder1 == node->parent()); | |
595 EXPECT_EQ(1, root->child_count()); | |
596 EXPECT_EQ(folder1, root->GetChild(0)); | |
597 EXPECT_EQ(1, folder1->child_count()); | |
598 EXPECT_EQ(node, folder1->GetChild(0)); | |
599 | |
600 // And remove the folder. | |
601 ClearCounts(); | |
602 model_->Remove(root, 0); | |
603 AssertObserverCount(0, 0, 1, 0, 0, 1, 0, 0, 0); | |
604 observer_details_.ExpectEquals(root, NULL, 0, -1); | |
605 EXPECT_TRUE(model_->GetMostRecentlyAddedNodeForURL(url) == NULL); | |
606 EXPECT_EQ(0, root->child_count()); | |
607 } | |
608 | |
609 TEST_F(BookmarkModelTest, NonMovingMoveCall) { | |
610 const BookmarkNode* root = model_->bookmark_bar_node(); | |
611 const base::string16 title(ASCIIToUTF16("foo")); | |
612 const GURL url("http://foo.com"); | |
613 const base::Time old_date(base::Time::Now() - base::TimeDelta::FromDays(1)); | |
614 | |
615 const BookmarkNode* node = model_->AddURL(root, 0, title, url); | |
616 model_->SetDateFolderModified(root, old_date); | |
617 | |
618 // Since |node| is already at the index 0 of |root|, this is no-op. | |
619 model_->Move(node, root, 0); | |
620 | |
621 // Check that the modification date is kept untouched. | |
622 EXPECT_EQ(old_date, root->date_folder_modified()); | |
623 } | |
624 | |
625 TEST_F(BookmarkModelTest, Copy) { | |
626 const BookmarkNode* root = model_->bookmark_bar_node(); | |
627 static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h "); | |
628 test::AddNodesFromModelString(model_.get(), root, model_string); | |
629 | |
630 // Validate initial model. | |
631 std::string actual_model_string = test::ModelStringFromNode(root); | |
632 EXPECT_EQ(model_string, actual_model_string); | |
633 | |
634 // Copy 'd' to be after '1:b': URL item from bar to folder. | |
635 const BookmarkNode* node_to_copy = root->GetChild(2); | |
636 const BookmarkNode* destination = root->GetChild(1); | |
637 model_->Copy(node_to_copy, destination, 1); | |
638 actual_model_string = test::ModelStringFromNode(root); | |
639 EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string); | |
640 | |
641 // Copy '1:d' to be after 'a': URL item from folder to bar. | |
642 const BookmarkNode* folder = root->GetChild(1); | |
643 node_to_copy = folder->GetChild(1); | |
644 model_->Copy(node_to_copy, root, 1); | |
645 actual_model_string = test::ModelStringFromNode(root); | |
646 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actual_model_string); | |
647 | |
648 // Copy '1' to be after '2:e': Folder from bar to folder. | |
649 node_to_copy = root->GetChild(2); | |
650 destination = root->GetChild(4); | |
651 model_->Copy(node_to_copy, destination, 1); | |
652 actual_model_string = test::ModelStringFromNode(root); | |
653 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ", | |
654 actual_model_string); | |
655 | |
656 // Copy '2:1' to be after '2:f': Folder within same folder. | |
657 folder = root->GetChild(4); | |
658 node_to_copy = folder->GetChild(1); | |
659 model_->Copy(node_to_copy, folder, 3); | |
660 actual_model_string = test::ModelStringFromNode(root); | |
661 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ", | |
662 actual_model_string); | |
663 | |
664 // Copy first 'd' to be after 'h': URL item within the bar. | |
665 node_to_copy = root->GetChild(1); | |
666 model_->Copy(node_to_copy, root, 6); | |
667 actual_model_string = test::ModelStringFromNode(root); | |
668 EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", | |
669 actual_model_string); | |
670 | |
671 // Copy '2' to be after 'a': Folder within the bar. | |
672 node_to_copy = root->GetChild(4); | |
673 model_->Copy(node_to_copy, root, 1); | |
674 actual_model_string = test::ModelStringFromNode(root); | |
675 EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] " | |
676 "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ", | |
677 actual_model_string); | |
678 } | |
679 | |
680 // Tests that adding a URL to a folder updates the last modified time. | |
681 TEST_F(BookmarkModelTest, ParentForNewNodes) { | |
682 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes()); | |
683 | |
684 const base::string16 title(ASCIIToUTF16("foo")); | |
685 const GURL url("http://foo.com"); | |
686 | |
687 model_->AddURL(model_->other_node(), 0, title, url); | |
688 ASSERT_EQ(model_->other_node(), model_->GetParentForNewNodes()); | |
689 } | |
690 | |
691 // Tests that adding a URL to a folder updates the last modified time. | |
692 TEST_F(BookmarkModelTest, ParentForNewMobileNodes) { | |
693 ASSERT_EQ(model_->bookmark_bar_node(), model_->GetParentForNewNodes()); | |
694 | |
695 const base::string16 title(ASCIIToUTF16("foo")); | |
696 const GURL url("http://foo.com"); | |
697 | |
698 model_->AddURL(model_->mobile_node(), 0, title, url); | |
699 ASSERT_EQ(model_->mobile_node(), model_->GetParentForNewNodes()); | |
700 } | |
701 | |
702 // Make sure recently modified stays in sync when adding a URL. | |
703 TEST_F(BookmarkModelTest, MostRecentlyModifiedFolders) { | |
704 // Add a folder. | |
705 const BookmarkNode* folder = | |
706 model_->AddFolder(model_->other_node(), 0, ASCIIToUTF16("foo")); | |
707 // Add a URL to it. | |
708 model_->AddURL(folder, 0, ASCIIToUTF16("blah"), GURL("http://foo.com")); | |
709 | |
710 // Make sure folder is in the most recently modified. | |
711 std::vector<const BookmarkNode*> most_recent_folders = | |
712 bookmark_utils::GetMostRecentlyModifiedFolders(model_.get(), 1); | |
713 ASSERT_EQ(1U, most_recent_folders.size()); | |
714 ASSERT_EQ(folder, most_recent_folders[0]); | |
715 | |
716 // Nuke the folder and do another fetch, making sure folder isn't in the | |
717 // returned list. | |
718 model_->Remove(folder->parent(), 0); | |
719 most_recent_folders = | |
720 bookmark_utils::GetMostRecentlyModifiedFolders(model_.get(), 1); | |
721 ASSERT_EQ(1U, most_recent_folders.size()); | |
722 ASSERT_TRUE(most_recent_folders[0] != folder); | |
723 } | |
724 | |
725 // Make sure MostRecentlyAddedEntries stays in sync. | |
726 TEST_F(BookmarkModelTest, MostRecentlyAddedEntries) { | |
727 // Add a couple of nodes such that the following holds for the time of the | |
728 // nodes: n1 > n2 > n3 > n4. | |
729 Time base_time = Time::Now(); | |
730 BookmarkNode* n1 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
731 0, | |
732 ASCIIToUTF16("blah"), | |
733 GURL("http://foo.com/0"))); | |
734 BookmarkNode* n2 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
735 1, | |
736 ASCIIToUTF16("blah"), | |
737 GURL("http://foo.com/1"))); | |
738 BookmarkNode* n3 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
739 2, | |
740 ASCIIToUTF16("blah"), | |
741 GURL("http://foo.com/2"))); | |
742 BookmarkNode* n4 = AsMutable(model_->AddURL(model_->bookmark_bar_node(), | |
743 3, | |
744 ASCIIToUTF16("blah"), | |
745 GURL("http://foo.com/3"))); | |
746 n1->set_date_added(base_time + TimeDelta::FromDays(4)); | |
747 n2->set_date_added(base_time + TimeDelta::FromDays(3)); | |
748 n3->set_date_added(base_time + TimeDelta::FromDays(2)); | |
749 n4->set_date_added(base_time + TimeDelta::FromDays(1)); | |
750 | |
751 // Make sure order is honored. | |
752 std::vector<const BookmarkNode*> recently_added; | |
753 bookmark_utils::GetMostRecentlyAddedEntries(model_.get(), 2, &recently_added); | |
754 ASSERT_EQ(2U, recently_added.size()); | |
755 ASSERT_TRUE(n1 == recently_added[0]); | |
756 ASSERT_TRUE(n2 == recently_added[1]); | |
757 | |
758 // swap 1 and 2, then check again. | |
759 recently_added.clear(); | |
760 SwapDateAdded(n1, n2); | |
761 bookmark_utils::GetMostRecentlyAddedEntries(model_.get(), 4, &recently_added); | |
762 ASSERT_EQ(4U, recently_added.size()); | |
763 ASSERT_TRUE(n2 == recently_added[0]); | |
764 ASSERT_TRUE(n1 == recently_added[1]); | |
765 ASSERT_TRUE(n3 == recently_added[2]); | |
766 ASSERT_TRUE(n4 == recently_added[3]); | |
767 } | |
768 | |
769 // Makes sure GetMostRecentlyAddedNodeForURL stays in sync. | |
770 TEST_F(BookmarkModelTest, GetMostRecentlyAddedNodeForURL) { | |
771 // Add a couple of nodes such that the following holds for the time of the | |
772 // nodes: n1 > n2 | |
773 Time base_time = Time::Now(); | |
774 const GURL url("http://foo.com/0"); | |
775 BookmarkNode* n1 = AsMutable(model_->AddURL( | |
776 model_->bookmark_bar_node(), 0, ASCIIToUTF16("blah"), url)); | |
777 BookmarkNode* n2 = AsMutable(model_->AddURL( | |
778 model_->bookmark_bar_node(), 1, ASCIIToUTF16("blah"), url)); | |
779 n1->set_date_added(base_time + TimeDelta::FromDays(4)); | |
780 n2->set_date_added(base_time + TimeDelta::FromDays(3)); | |
781 | |
782 // Make sure order is honored. | |
783 ASSERT_EQ(n1, model_->GetMostRecentlyAddedNodeForURL(url)); | |
784 | |
785 // swap 1 and 2, then check again. | |
786 SwapDateAdded(n1, n2); | |
787 ASSERT_EQ(n2, model_->GetMostRecentlyAddedNodeForURL(url)); | |
788 } | |
789 | |
790 // Makes sure GetBookmarks removes duplicates. | |
791 TEST_F(BookmarkModelTest, GetBookmarksWithDups) { | |
792 const GURL url("http://foo.com/0"); | |
793 const base::string16 title(ASCIIToUTF16("blah")); | |
794 model_->AddURL(model_->bookmark_bar_node(), 0, title, url); | |
795 model_->AddURL(model_->bookmark_bar_node(), 1, title, url); | |
796 | |
797 std::vector<BookmarkService::URLAndTitle> bookmarks; | |
798 model_->GetBookmarks(&bookmarks); | |
799 ASSERT_EQ(1U, bookmarks.size()); | |
800 EXPECT_EQ(url, bookmarks[0].url); | |
801 EXPECT_EQ(title, bookmarks[0].title); | |
802 | |
803 model_->AddURL(model_->bookmark_bar_node(), 2, ASCIIToUTF16("Title2"), url); | |
804 // Only one returned, even titles are different. | |
805 bookmarks.clear(); | |
806 model_->GetBookmarks(&bookmarks); | |
807 EXPECT_EQ(1U, bookmarks.size()); | |
808 } | |
809 | |
810 TEST_F(BookmarkModelTest, HasBookmarks) { | |
811 const GURL url("http://foo.com/"); | |
812 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url); | |
813 | |
814 EXPECT_TRUE(model_->HasBookmarks()); | |
815 } | |
816 | |
817 // See comment in PopulateNodeFromString. | |
818 typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode; | |
819 | |
820 // Does the work of PopulateNodeFromString. index gives the index of the current | |
821 // element in description to process. | |
822 void PopulateNodeImpl(const std::vector<std::string>& description, | |
823 size_t* index, | |
824 TestNode* parent) { | |
825 while (*index < description.size()) { | |
826 const std::string& element = description[*index]; | |
827 (*index)++; | |
828 if (element == "[") { | |
829 // Create a new folder and recurse to add all the children. | |
830 // Folders are given a unique named by way of an ever increasing integer | |
831 // value. The folders need not have a name, but one is assigned to help | |
832 // in debugging. | |
833 static int next_folder_id = 1; | |
834 TestNode* new_node = | |
835 new TestNode(base::IntToString16(next_folder_id++), | |
836 BookmarkNode::FOLDER); | |
837 parent->Add(new_node, parent->child_count()); | |
838 PopulateNodeImpl(description, index, new_node); | |
839 } else if (element == "]") { | |
840 // End the current folder. | |
841 return; | |
842 } else { | |
843 // Add a new URL. | |
844 | |
845 // All tokens must be space separated. If there is a [ or ] in the name it | |
846 // likely means a space was forgotten. | |
847 DCHECK(element.find('[') == std::string::npos); | |
848 DCHECK(element.find(']') == std::string::npos); | |
849 parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), | |
850 parent->child_count()); | |
851 } | |
852 } | |
853 } | |
854 | |
855 // Creates and adds nodes to parent based on description. description consists | |
856 // of the following tokens (all space separated): | |
857 // [ : creates a new USER_FOLDER node. All elements following the [ until the | |
858 // next balanced ] is encountered are added as children to the node. | |
859 // ] : closes the last folder created by [ so that any further nodes are added | |
860 // to the current folders parent. | |
861 // text: creates a new URL node. | |
862 // For example, "a [b] c" creates the following nodes: | |
863 // a 1 c | |
864 // | | |
865 // b | |
866 // In words: a node of type URL with the title a, followed by a folder node with | |
867 // the title 1 having the single child of type url with name b, followed by | |
868 // the url node with the title c. | |
869 // | |
870 // NOTE: each name must be unique, and folders are assigned a unique title by | |
871 // way of an increasing integer. | |
872 void PopulateNodeFromString(const std::string& description, TestNode* parent) { | |
873 std::vector<std::string> elements; | |
874 base::SplitStringAlongWhitespace(description, &elements); | |
875 size_t index = 0; | |
876 PopulateNodeImpl(elements, &index, parent); | |
877 } | |
878 | |
879 // Populates the BookmarkNode with the children of parent. | |
880 void PopulateBookmarkNode(TestNode* parent, | |
881 BookmarkModel* model, | |
882 const BookmarkNode* bb_node) { | |
883 for (int i = 0; i < parent->child_count(); ++i) { | |
884 TestNode* child = parent->GetChild(i); | |
885 if (child->value == BookmarkNode::FOLDER) { | |
886 const BookmarkNode* new_bb_node = | |
887 model->AddFolder(bb_node, i, child->GetTitle()); | |
888 PopulateBookmarkNode(child, model, new_bb_node); | |
889 } else { | |
890 model->AddURL(bb_node, i, child->GetTitle(), | |
891 GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); | |
892 } | |
893 } | |
894 } | |
895 | |
896 // Test class that creates a BookmarkModel with a real history backend. | |
897 class BookmarkModelTestWithProfile : public testing::Test { | |
898 public: | |
899 BookmarkModelTestWithProfile() {} | |
900 | |
901 protected: | |
902 // Verifies the contents of the bookmark bar node match the contents of the | |
903 // TestNode. | |
904 void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { | |
905 ASSERT_EQ(expected->child_count(), actual->child_count()); | |
906 for (int i = 0; i < expected->child_count(); ++i) { | |
907 TestNode* expected_child = expected->GetChild(i); | |
908 const BookmarkNode* actual_child = actual->GetChild(i); | |
909 ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); | |
910 if (expected_child->value == BookmarkNode::FOLDER) { | |
911 ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); | |
912 // Recurse throught children. | |
913 VerifyModelMatchesNode(expected_child, actual_child); | |
914 if (HasFatalFailure()) | |
915 return; | |
916 } else { | |
917 // No need to check the URL, just the title is enough. | |
918 ASSERT_TRUE(actual_child->is_url()); | |
919 } | |
920 } | |
921 } | |
922 | |
923 void VerifyNoDuplicateIDs(BookmarkModel* model) { | |
924 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); | |
925 base::hash_set<int64> ids; | |
926 while (it.has_next()) | |
927 ASSERT_TRUE(ids.insert(it.Next()->id()).second); | |
928 } | |
929 | |
930 test::TestBookmarkClient client_; | |
931 scoped_ptr<BookmarkModel> model_; | |
932 }; | |
933 | |
934 // Creates a set of nodes in the bookmark bar model, then recreates the | |
935 // bookmark bar model which triggers loading from the db and checks the loaded | |
936 // structure to make sure it is what we first created. | |
937 TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) { | |
938 struct TestData { | |
939 // Structure of the children of the bookmark bar model node. | |
940 const std::string bbn_contents; | |
941 // Structure of the children of the other node. | |
942 const std::string other_contents; | |
943 // Structure of the children of the synced node. | |
944 const std::string mobile_contents; | |
945 } data[] = { | |
946 // See PopulateNodeFromString for a description of these strings. | |
947 { "", "" }, | |
948 { "a", "b" }, | |
949 { "a [ b ]", "" }, | |
950 { "", "[ b ] a [ c [ d e [ f ] ] ]" }, | |
951 { "a [ b ]", "" }, | |
952 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, | |
953 }; | |
954 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { | |
955 model_ = client_.CreateModel(false); | |
956 | |
957 TestNode bbn; | |
958 PopulateNodeFromString(data[i].bbn_contents, &bbn); | |
959 PopulateBookmarkNode(&bbn, model_.get(), model_->bookmark_bar_node()); | |
960 | |
961 TestNode other; | |
962 PopulateNodeFromString(data[i].other_contents, &other); | |
963 PopulateBookmarkNode(&other, model_.get(), model_->other_node()); | |
964 | |
965 TestNode mobile; | |
966 PopulateNodeFromString(data[i].mobile_contents, &mobile); | |
967 PopulateBookmarkNode(&mobile, model_.get(), model_->mobile_node()); | |
968 | |
969 VerifyModelMatchesNode(&bbn, model_->bookmark_bar_node()); | |
970 VerifyModelMatchesNode(&other, model_->other_node()); | |
971 VerifyModelMatchesNode(&mobile, model_->mobile_node()); | |
972 VerifyNoDuplicateIDs(model_.get()); | |
973 } | |
974 } | |
975 | |
976 TEST_F(BookmarkModelTest, Sort) { | |
977 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'. | |
978 // 'C' and 'a' are folders. | |
979 TestNode bbn; | |
980 PopulateNodeFromString("B [ a ] d [ a ]", &bbn); | |
981 const BookmarkNode* parent = model_->bookmark_bar_node(); | |
982 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
983 | |
984 BookmarkNode* child1 = AsMutable(parent->GetChild(1)); | |
985 child1->SetTitle(ASCIIToUTF16("a")); | |
986 delete child1->Remove(child1->GetChild(0)); | |
987 BookmarkNode* child3 = AsMutable(parent->GetChild(3)); | |
988 child3->SetTitle(ASCIIToUTF16("C")); | |
989 delete child3->Remove(child3->GetChild(0)); | |
990 | |
991 ClearCounts(); | |
992 | |
993 // Sort the children of the bookmark bar node. | |
994 model_->SortChildren(parent); | |
995 | |
996 // Make sure we were notified. | |
997 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0); | |
998 | |
999 // Make sure the order matches (remember, 'a' and 'C' are folders and | |
1000 // come first). | |
1001 EXPECT_EQ(parent->GetChild(0)->GetTitle(), ASCIIToUTF16("a")); | |
1002 EXPECT_EQ(parent->GetChild(1)->GetTitle(), ASCIIToUTF16("C")); | |
1003 EXPECT_EQ(parent->GetChild(2)->GetTitle(), ASCIIToUTF16("B")); | |
1004 EXPECT_EQ(parent->GetChild(3)->GetTitle(), ASCIIToUTF16("d")); | |
1005 } | |
1006 | |
1007 TEST_F(BookmarkModelTest, Reorder) { | |
1008 // Populate the bookmark bar node with nodes 'A', 'B', 'C' and 'D'. | |
1009 TestNode bbn; | |
1010 PopulateNodeFromString("A B C D", &bbn); | |
1011 BookmarkNode* parent = AsMutable(model_->bookmark_bar_node()); | |
1012 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
1013 | |
1014 ClearCounts(); | |
1015 | |
1016 // Reorder bar node's bookmarks in reverse order. | |
1017 std::vector<const BookmarkNode*> new_order; | |
1018 new_order.push_back(parent->GetChild(3)); | |
1019 new_order.push_back(parent->GetChild(2)); | |
1020 new_order.push_back(parent->GetChild(1)); | |
1021 new_order.push_back(parent->GetChild(0)); | |
1022 model_->ReorderChildren(parent, new_order); | |
1023 | |
1024 // Make sure we were notified. | |
1025 AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 0); | |
1026 | |
1027 // Make sure the order matches is correct (it should be reversed). | |
1028 ASSERT_EQ(4, parent->child_count()); | |
1029 EXPECT_EQ("D", base::UTF16ToASCII(parent->GetChild(0)->GetTitle())); | |
1030 EXPECT_EQ("C", base::UTF16ToASCII(parent->GetChild(1)->GetTitle())); | |
1031 EXPECT_EQ("B", base::UTF16ToASCII(parent->GetChild(2)->GetTitle())); | |
1032 EXPECT_EQ("A", base::UTF16ToASCII(parent->GetChild(3)->GetTitle())); | |
1033 } | |
1034 | |
1035 TEST_F(BookmarkModelTest, NodeVisibility) { | |
1036 // Mobile node invisible by default | |
1037 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible()); | |
1038 EXPECT_TRUE(model_->other_node()->IsVisible()); | |
1039 EXPECT_FALSE(model_->mobile_node()->IsVisible()); | |
1040 | |
1041 // Visibility of permanent node can only be changed if they are not | |
1042 // forced to be visible by the client. | |
1043 model_->SetPermanentNodeVisible(BookmarkNode::BOOKMARK_BAR, false); | |
1044 EXPECT_TRUE(model_->bookmark_bar_node()->IsVisible()); | |
1045 model_->SetPermanentNodeVisible(BookmarkNode::OTHER_NODE, false); | |
1046 EXPECT_TRUE(model_->other_node()->IsVisible()); | |
1047 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, true); | |
1048 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
1049 model_->SetPermanentNodeVisible(BookmarkNode::MOBILE, false); | |
1050 EXPECT_FALSE(model_->mobile_node()->IsVisible()); | |
1051 | |
1052 // Arbitrary node should be visible | |
1053 TestNode bbn; | |
1054 PopulateNodeFromString("B", &bbn); | |
1055 const BookmarkNode* parent = model_->mobile_node(); | |
1056 PopulateBookmarkNode(&bbn, model_.get(), parent); | |
1057 EXPECT_TRUE(parent->GetChild(0)->IsVisible()); | |
1058 | |
1059 // Mobile folder should be visible now that it has a child. | |
1060 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
1061 } | |
1062 | |
1063 TEST_F(BookmarkModelTest, MobileNodeVisibileWithChildren) { | |
1064 const BookmarkNode* root = model_->mobile_node(); | |
1065 const base::string16 title(ASCIIToUTF16("foo")); | |
1066 const GURL url("http://foo.com"); | |
1067 | |
1068 model_->AddURL(root, 0, title, url); | |
1069 EXPECT_TRUE(model_->mobile_node()->IsVisible()); | |
1070 } | |
1071 | |
1072 TEST_F(BookmarkModelTest, ExtensiveChangesObserver) { | |
1073 AssertExtensiveChangesObserverCount(0, 0); | |
1074 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
1075 model_->BeginExtensiveChanges(); | |
1076 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
1077 AssertExtensiveChangesObserverCount(1, 0); | |
1078 model_->EndExtensiveChanges(); | |
1079 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
1080 AssertExtensiveChangesObserverCount(1, 1); | |
1081 } | |
1082 | |
1083 TEST_F(BookmarkModelTest, MultipleExtensiveChangesObserver) { | |
1084 AssertExtensiveChangesObserverCount(0, 0); | |
1085 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
1086 model_->BeginExtensiveChanges(); | |
1087 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
1088 AssertExtensiveChangesObserverCount(1, 0); | |
1089 model_->BeginExtensiveChanges(); | |
1090 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
1091 AssertExtensiveChangesObserverCount(1, 0); | |
1092 model_->EndExtensiveChanges(); | |
1093 EXPECT_TRUE(model_->IsDoingExtensiveChanges()); | |
1094 AssertExtensiveChangesObserverCount(1, 0); | |
1095 model_->EndExtensiveChanges(); | |
1096 EXPECT_FALSE(model_->IsDoingExtensiveChanges()); | |
1097 AssertExtensiveChangesObserverCount(1, 1); | |
1098 } | |
1099 | |
1100 TEST(BookmarkNodeTest, NodeMetaInfo) { | |
1101 GURL url; | |
1102 BookmarkNode node(url); | |
1103 EXPECT_FALSE(node.GetMetaInfoMap()); | |
1104 | |
1105 EXPECT_TRUE(node.SetMetaInfo("key1", "value1")); | |
1106 std::string out_value; | |
1107 EXPECT_TRUE(node.GetMetaInfo("key1", &out_value)); | |
1108 EXPECT_EQ("value1", out_value); | |
1109 EXPECT_FALSE(node.SetMetaInfo("key1", "value1")); | |
1110 | |
1111 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
1112 EXPECT_TRUE(node.SetMetaInfo("key2.subkey1", "value2")); | |
1113 EXPECT_TRUE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
1114 EXPECT_EQ("value2", out_value); | |
1115 | |
1116 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
1117 EXPECT_TRUE(node.SetMetaInfo("key2.subkey2.leaf", "")); | |
1118 EXPECT_TRUE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
1119 EXPECT_EQ("", out_value); | |
1120 | |
1121 EXPECT_TRUE(node.DeleteMetaInfo("key1")); | |
1122 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1")); | |
1123 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf")); | |
1124 EXPECT_FALSE(node.DeleteMetaInfo("key3")); | |
1125 EXPECT_FALSE(node.GetMetaInfo("key1", &out_value)); | |
1126 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); | |
1127 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value)); | |
1128 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | |
1129 EXPECT_FALSE(node.GetMetaInfoMap()); | |
1130 } | |
1131 | |
1132 } // namespace | |
OLD | NEW |