1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <set>
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <string>
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/base_paths.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_util.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/hash_tables.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/path_service.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string16.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/string_split.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_codec.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_model.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/bookmarks/bookmark_utils.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/history_notifications.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/test/model_test_utils.h"
24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/test/testing_browser_process_test.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/test/testing_profile.h"
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h"
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_registrar.h"
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h"
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/models/tree_node_iterator.h"
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/models/tree_node_model.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Helper to get a mutable bookmark node.
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic BookmarkNode* AsMutable(const BookmarkNode* node) {
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return const_cast<BookmarkNode*>(node);
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time tmp = n1->date_added();
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n1->set_date_added(n2->date_added());
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n2->set_date_added(tmp);
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // anonymous namespace
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenclass BookmarkModelTest : public TestingBrowserProcessTest,
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          public BookmarkModelObserver {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  struct ObserverDetails {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ObserverDetails() {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      Set(NULL, NULL, -1, -1);
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    void Set(const BookmarkNode* node1,
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             const BookmarkNode* node2,
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             int index1,
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             int index2) {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this->node1 = node1;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this->node2 = node2;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this->index1 = index1;
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this->index2 = index2;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    void AssertEquals(const BookmarkNode* node1,
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      const BookmarkNode* node2,
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      int index1,
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      int index2) {
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_TRUE(this->node1 == node1);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_TRUE(this->node2 == node2);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_EQ(index1, this->index1);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_EQ(index2, this->index2);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* node1;
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* node2;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index1;
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int index2;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModelTest() : model(NULL) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model.AddObserver(this);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ClearCounts();
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Loaded(BookmarkModel* model) {
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We never load from the db, so that this should never get invoked.
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NOTREACHED();
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeMoved(BookmarkModel* model,
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* old_parent,
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int old_index,
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* new_parent,
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int new_index) {
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    moved_count++;
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    observer_details.Set(old_parent, new_parent, old_index, new_index);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeAdded(BookmarkModel* model,
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* parent,
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int index) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    added_count++;
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    observer_details.Set(parent, NULL, index, -1);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeRemoved(BookmarkModel* model,
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* parent,
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   int old_index,
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* node) {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    removed_count++;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    observer_details.Set(parent, NULL, old_index, -1);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeChanged(BookmarkModel* model,
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* node) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    changed_count++;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    observer_details.Set(node, NULL, -1, -1);
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const BookmarkNode* node) {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    reordered_count_++;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model,
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const BookmarkNode* node) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We never attempt to load favicons, so that this method never
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // gets invoked.
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void ClearCounts() {
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    reordered_count_ = moved_count = added_count = removed_count =
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        changed_count = 0;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void AssertObserverCount(int added_count,
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           int moved_count,
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           int removed_count,
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           int changed_count,
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           int reordered_count) {
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(added_count, this->added_count);
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(moved_count, this->moved_count);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(removed_count, this->removed_count);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(changed_count, this->changed_count);
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(reordered_count, reordered_count_);
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModel model;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int moved_count;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int added_count;
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int removed_count;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int changed_count;
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int reordered_count_;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ObserverDetails observer_details;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, InitialState) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* bb_node = model.GetBookmarkBarNode();
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(bb_node != NULL);
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(0, bb_node->child_count());
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(BookmarkNode::BOOKMARK_BAR, bb_node->type());
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* other_node = model.other_node();
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(other_node != NULL);
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(0, other_node->child_count());
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(BookmarkNode::OTHER_NODE, other_node->type());
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(bb_node->id() != other_node->id());
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, AddURL) {
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* new_node = model.AddURL(root, 0, title, url);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(1, 0, 0, 0, 0);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(1, root->child_count());
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(title, new_node->GetTitle());
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(url == new_node->GetURL());
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(BookmarkNode::URL, new_node->type());
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(new_node == model.GetMostRecentlyAddedNodeForURL(url));
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(new_node->id() != root->id() &&
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              new_node->id() != model.other_node()->id());
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(BookmarkModelTest, AddFolder) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* new_node = model.AddFolder(root, 0, title);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(1, 0, 0, 0, 0);
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(1, root->child_count());
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(title, new_node->GetTitle());
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(BookmarkNode::FOLDER, new_node->type());
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(new_node->id() != root->id() &&
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              new_node->id() != model.other_node()->id());
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Add another folder, just to make sure folder_ids are incremented correctly.
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.AddFolder(root, 0, title);
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(1, 0, 0, 0, 0);
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, RemoveURL) {
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
2273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.AddURL(root, 0, title, url);
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Remove(root, 0);
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(0, root->child_count());
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 1, 0, 0);
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure there is no mapping for the URL.
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(model.GetMostRecentlyAddedNodeForURL(url) == NULL);
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(BookmarkModelTest, RemoveFolder) {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* folder = model.AddFolder(root, 0, ASCIIToUTF16("foo"));
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add a URL as a child.
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.AddURL(folder, 0, title, url);
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Now remove the folder.
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Remove(root, 0);
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(0, root->child_count());
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 1, 0, 0);
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure there is no mapping for the URL.
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(model.GetMostRecentlyAddedNodeForURL(url) == NULL);
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, SetTitle) {
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  string16 title(ASCIIToUTF16("foo"));
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = model.AddURL(root, 0, title, url);
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  title = ASCIIToUTF16("foo2");
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.SetTitle(node, title);
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 0, 1, 0);
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(node, NULL, -1, -1);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(title, node->GetTitle());
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, SetURL) {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url("http://foo.com");
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = model.AddURL(root, 0, title, url);
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url = GURL("http://foo2.com");
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.SetURL(node, url);
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 0, 1, 0);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(node, NULL, -1, -1);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(url, node->GetURL());
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, Move) {
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* node = model.AddURL(root, 0, title, url);
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* folder1 = model.AddFolder(root, 0, ASCIIToUTF16("foo"));
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.Move(node, folder1, 0);
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 1, 0, 0, 0);
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  observer_details.AssertEquals(root, folder1, 1, 0);
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_TRUE(folder1 == node->parent());
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(1, root->child_count());
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(folder1, root->GetChild(0));
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(1, folder1->child_count());
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(node, folder1->GetChild(0));
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // And remove the folder.
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Remove(root, 0);
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 1, 0, 0);
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  observer_details.AssertEquals(root, NULL, 0, -1);
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(model.GetMostRecentlyAddedNodeForURL(url) == NULL);
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXPECT_EQ(0, root->child_count());
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, Copy) {
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* root = model.GetBookmarkBarNode();
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const std::string model_string("a 1:[ b c ] d 2:[ e f g ] h ");
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model_test_utils::AddNodesFromModelString(model, root, model_string);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Validate initial model.
3273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string actualModelString = model_test_utils::ModelStringFromNode(root);
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(model_string, actualModelString);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy 'd' to be after '1:b': URL item from bar to folder.
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* nodeToCopy = root->GetChild(2);
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* destination = root->GetChild(1);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Copy(nodeToCopy, destination, 1);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy '1:d' to be after 'a': URL item from folder to bar.
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* folder = root->GetChild(1);
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  nodeToCopy = folder->GetChild(1);
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Copy(nodeToCopy, root, 1);
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a d 1:[ b d c ] d 2:[ e f g ] h ", actualModelString);
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy '1' to be after '2:e': Folder from bar to folder.
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  nodeToCopy = root->GetChild(2);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  destination = root->GetChild(4);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Copy(nodeToCopy, destination, 1);
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f g ] h ", actualModelString);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy '2:1' to be after '2:f': Folder within same folder.
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  folder = root->GetChild(4);
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  nodeToCopy = folder->GetChild(1);
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.Copy(nodeToCopy, folder, 3);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h ",
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            actualModelString);
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy first 'd' to be after 'h': URL item within the bar.
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  nodeToCopy = root->GetChild(1);
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Copy(nodeToCopy, root, 6);
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a d 1:[ b d c ] d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            actualModelString);
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy '2' to be after 'a': Folder within the bar.
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  nodeToCopy = root->GetChild(4);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.Copy(nodeToCopy, root, 1);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  actualModelString = model_test_utils::ModelStringFromNode(root);
3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ("a 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] d 1:[ b d c ] "
3713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            "d 2:[ e 1:[ b d c ] f 1:[ b d c ] g ] h d ",
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            actualModelString);
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tests that adding a URL to a folder updates the last modified time.
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, ParentForNewNodes) {
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(model.GetBookmarkBarNode(), model.GetParentForNewNodes());
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const string16 title(ASCIIToUTF16("foo"));
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com");
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.AddURL(model.other_node(), 0, title, url);
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(model.other_node(), model.GetParentForNewNodes());
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Make sure recently modified stays in sync when adding a URL.
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenTEST_F(BookmarkModelTest, MostRecentlyModifiedFolders) {
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Add a folder.
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const BookmarkNode* folder = model.AddFolder(model.other_node(), 0,
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                               ASCIIToUTF16("foo"));
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add a URL to it.
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.AddURL(folder, 0, ASCIIToUTF16("blah"), GURL("http://foo.com"));
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make sure folder is in the most recently modified.
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<const BookmarkNode*> most_recent_folders =
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      bookmark_utils::GetMostRecentlyModifiedFolders(&model, 1);
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(1U, most_recent_folders.size());
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(folder, most_recent_folders[0]);
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Nuke the folder and do another fetch, making sure folder isn't in the
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // returned list.
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.Remove(folder->parent(), 0);
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  most_recent_folders =
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      bookmark_utils::GetMostRecentlyModifiedFolders(&model, 1);
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_EQ(1U, most_recent_folders.size());
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ASSERT_TRUE(most_recent_folders[0] != folder);
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Make sure MostRecentlyAddedEntries stays in sync.
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, MostRecentlyAddedEntries) {
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add a couple of nodes such that the following holds for the time of the
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // nodes: n1 > n2 > n3 > n4.
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time base_time = Time::Now();
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n1 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  0,
4163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  ASCIIToUTF16("blah"),
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  GURL("http://foo.com/0")));
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n2 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  1,
4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  ASCIIToUTF16("blah"),
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  GURL("http://foo.com/1")));
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n3 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  2,
4243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  ASCIIToUTF16("blah"),
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  GURL("http://foo.com/2")));
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n4 = AsMutable(model.AddURL(model.GetBookmarkBarNode(),
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  3,
4283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                  ASCIIToUTF16("blah"),
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  GURL("http://foo.com/3")));
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n1->set_date_added(base_time + TimeDelta::FromDays(4));
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n2->set_date_added(base_time + TimeDelta::FromDays(3));
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n3->set_date_added(base_time + TimeDelta::FromDays(2));
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n4->set_date_added(base_time + TimeDelta::FromDays(1));
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure order is honored.
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<const BookmarkNode*> recently_added;
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_utils::GetMostRecentlyAddedEntries(&model, 2, &recently_added);
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(2U, recently_added.size());
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n1 == recently_added[0]);
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n2 == recently_added[1]);
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // swap 1 and 2, then check again.
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  recently_added.clear();
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SwapDateAdded(n1, n2);
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bookmark_utils::GetMostRecentlyAddedEntries(&model, 4, &recently_added);
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(4U, recently_added.size());
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n2 == recently_added[0]);
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n1 == recently_added[1]);
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n3 == recently_added[2]);
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(n4 == recently_added[3]);
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Makes sure GetMostRecentlyAddedNodeForURL stays in sync.
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, GetMostRecentlyAddedNodeForURL) {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add a couple of nodes such that the following holds for the time of the
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // nodes: n1 > n2
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Time base_time = Time::Now();
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com/0");
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n1 = AsMutable(model.AddURL(
4603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url));
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* n2 = AsMutable(model.AddURL(
4623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url));
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n1->set_date_added(base_time + TimeDelta::FromDays(4));
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n2->set_date_added(base_time + TimeDelta::FromDays(3));
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure order is honored.
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(n1, model.GetMostRecentlyAddedNodeForURL(url));
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // swap 1 and 2, then check again.
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SwapDateAdded(n1, n2);
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(n2, model.GetMostRecentlyAddedNodeForURL(url));
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Makes sure GetBookmarks removes duplicates.
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, GetBookmarksWithDups) {
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com/0");
4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  model.AddURL(model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url);
4783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  model.AddURL(model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url);
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<GURL> urls;
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.GetBookmarks(&urls);
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1U, urls.size());
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(urls[0] == url);
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4863345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTEST_F(BookmarkModelTest, HasBookmarks) {
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const GURL url("http://foo.com/");
4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  model.AddURL(model.GetBookmarkBarNode(), 0, ASCIIToUTF16("bar"), url);
4893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_TRUE(model.HasBookmarks());
4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NotificationObserver implementation used in verifying we've received the
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// NOTIFY_URLS_STARRED method correctly.
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass StarredListener : public NotificationObserver {
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StarredListener() : notification_count_(0), details_(false) {
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    registrar_.Add(this, NotificationType::URLS_STARRED, Source<Profile>(NULL));
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Observe(NotificationType type,
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationSource& source,
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       const NotificationDetails& details) {
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (type == NotificationType::URLS_STARRED) {
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      notification_count_++;
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      details_ = *(Details<history::URLsStarredDetails>(details).ptr());
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Number of times NOTIFY_URLS_STARRED has been observed.
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int notification_count_;
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Details from the last NOTIFY_URLS_STARRED.
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  history::URLsStarredDetails details_;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(StarredListener);
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Makes sure NOTIFY_URLS_STARRED is sent correctly.
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, NotifyURLsStarred) {
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StarredListener listener;
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const GURL url("http://foo.com/0");
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* n1 = model.AddURL(
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      model.GetBookmarkBarNode(), 0, ASCIIToUTF16("blah"), url);
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Starred notification should be sent.
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, listener.notification_count_);
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(listener.details_.starred);
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(1U, listener.details_.changed_urls.size());
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(url == *(listener.details_.changed_urls.begin()));
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  listener.notification_count_ = 0;
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  listener.details_.changed_urls.clear();
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add another bookmark for the same URL. This should not send any
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // notification.
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* n2 = model.AddURL(
5443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      model.GetBookmarkBarNode(), 1, ASCIIToUTF16("blah"), url);
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, listener.notification_count_);
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove n2.
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.Remove(n2->parent(), 1);
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  n2 = NULL;
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Shouldn't have received any notification as n1 still exists with the same
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // URL.
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, listener.notification_count_);
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(model.GetMostRecentlyAddedNodeForURL(url) == n1);
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Remove n1.
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  model.Remove(n1->parent(), 0);
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now we should get the notification.
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, listener.notification_count_);
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_FALSE(listener.details_.starred);
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_EQ(1U, listener.details_.changed_urls.size());
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(url == *(listener.details_.changed_urls.begin()));
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See comment in PopulateNodeFromString.
57172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsentypedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode;
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Does the work of PopulateNodeFromString. index gives the index of the current
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// element in description to process.
5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic void PopulateNodeImpl(const std::vector<std::string>& description,
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             size_t* index,
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             TestNode* parent) {
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (*index < description.size()) {
5793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string& element = description[*index];
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    (*index)++;
5813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (element == "[") {
582ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Create a new folder and recurse to add all the children.
583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Folders are given a unique named by way of an ever increasing integer
584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // value. The folders need not have a name, but one is assigned to help
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // in debugging.
586ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static int next_folder_id = 1;
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TestNode* new_node =
588ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          new TestNode(base::IntToString16(next_folder_id++),
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       BookmarkNode::FOLDER);
590ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      parent->Add(new_node, parent->child_count());
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PopulateNodeImpl(description, index, new_node);
5923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else if (element == "]") {
593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // End the current folder.
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add a new URL.
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // All tokens must be space separated. If there is a [ or ] in the name it
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // likely means a space was forgotten.
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(element.find('[') == std::string::npos);
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK(element.find(']') == std::string::npos);
602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      parent->Add(new TestNode(UTF8ToUTF16(element), BookmarkNode::URL),
603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  parent->child_count());
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Creates and adds nodes to parent based on description. description consists
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// of the following tokens (all space separated):
610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//   [ : creates a new USER_FOLDER node. All elements following the [ until the
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//       next balanced ] is encountered are added as children to the node.
612ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//   ] : closes the last folder created by [ so that any further nodes are added
613ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen//       to the current folders parent.
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   text: creates a new URL node.
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// For example, "a [b] c" creates the following nodes:
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   a 1 c
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//     |
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//     b
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// In words: a node of type URL with the title a, followed by a folder node with
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the title 1 having the single child of type url with name b, followed by
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the url node with the title c.
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// NOTE: each name must be unique, and folders are assigned a unique title by
624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// way of an increasing integer.
6253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic void PopulateNodeFromString(const std::string& description,
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   TestNode* parent) {
6273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<std::string> elements;
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t index = 0;
6294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::SplitStringAlongWhitespace(description, &elements);
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PopulateNodeImpl(elements, &index, parent);
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Populates the BookmarkNode with the children of parent.
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void PopulateBookmarkNode(TestNode* parent,
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 BookmarkModel* model,
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* bb_node) {
637ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < parent->child_count(); ++i) {
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TestNode* child = parent->GetChild(i);
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (child->value == BookmarkNode::FOLDER) {
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const BookmarkNode* new_bb_node =
641ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          model->AddFolder(bb_node, i, child->GetTitle());
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PopulateBookmarkNode(child, model, new_bb_node);
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      model->AddURL(bb_node, i, child->GetTitle(),
6453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          GURL("http://" + UTF16ToASCII(child->GetTitle())));
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test class that creates a BookmarkModel with a real history backend.
653dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenclass BookmarkModelTestWithProfile : public TestingBrowserProcessTest,
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     public BookmarkModelObserver {
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModelTestWithProfile()
657731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      : ui_thread_(BrowserThread::UI, &message_loop_),
658731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        file_thread_(BrowserThread::FILE, &message_loop_) {}
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SetUp() {
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void TearDown() {
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(NULL);
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The profile.
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<TestingProfile> profile_;
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Verifies the contents of the bookmark bar node match the contents of the
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TestNode.
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) {
674ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(expected->child_count(), actual->child_count());
675ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (int i = 0; i < expected->child_count(); ++i) {
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      TestNode* expected_child = expected->GetChild(i);
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const BookmarkNode* actual_child = actual->GetChild(i);
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle());
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (expected_child->value == BookmarkNode::FOLDER) {
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER);
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Recurse throught children.
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        VerifyModelMatchesNode(expected_child, actual_child);
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (HasFatalFailure())
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return;
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // No need to check the URL, just the title is enough.
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ASSERT_TRUE(actual_child->type() == BookmarkNode::URL);
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void VerifyNoDuplicateIDs(BookmarkModel* model) {
69372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ui::TreeNodeIterator<const BookmarkNode> it(model->root_node());
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::hash_set<int64> ids;
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (it.has_next())
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ASSERT_TRUE(ids.insert(it.Next()->id()).second);
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void BlockTillBookmarkModelLoaded() {
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bb_model_ = profile_->GetBookmarkModel();
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!bb_model_->IsLoaded())
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      BlockTillLoaded(bb_model_);
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bb_model_->AddObserver(this);
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Destroys the current profile, creates a new one and creates the history
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // service.
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void RecreateProfile() {
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Need to shutdown the old one before creating a new one.
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(NULL);
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(new TestingProfile());
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_->CreateHistoryService(true, false);
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkModel* bb_model_;
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Blocks until the BookmarkModel has finished loading.
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void BlockTillLoaded(BookmarkModel* model) {
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    model->AddObserver(this);
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->Run();
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // BookmarkModelObserver methods.
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Loaded(BookmarkModel* model) {
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Balances the call in BlockTillLoaded.
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->Quit();
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeMoved(BookmarkModel* model,
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* old_parent,
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int old_index,
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* new_parent,
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int new_index) {}
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeAdded(BookmarkModel* model,
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 const BookmarkNode* parent,
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 int index) {}
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeRemoved(BookmarkModel* model,
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* parent,
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   int old_index,
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* node) {}
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeChanged(BookmarkModel* model,
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   const BookmarkNode* node) {}
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void BookmarkNodeChildrenReordered(BookmarkModel* model,
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                             const BookmarkNode* node) {}
746ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void BookmarkNodeFaviconLoaded(BookmarkModel* model,
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         const BookmarkNode* node) {}
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoopForUI message_loop_;
750731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread ui_thread_;
751731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread file_thread_;
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Creates a set of nodes in the bookmark bar model, then recreates the
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// bookmark bar model which triggers loading from the db and checks the loaded
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// structure to make sure it is what we first created.
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTestWithProfile, CreateAndRestore) {
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  struct TestData {
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Structure of the children of the bookmark bar model node.
7603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string bbn_contents;
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Structure of the children of the other node.
7623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const std::string other_contents;
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } data[] = {
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See PopulateNodeFromString for a description of these strings.
7653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "", "" },
7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "a", "b" },
7673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "a [ b ]", "" },
7683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "", "[ b ] a [ c [ d e [ f ] ] ]" },
7693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "a [ b ]", "" },
7703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"},
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) {
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Recreate the profile. We need to reset with NULL first so that the last
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // HistoryService releases the locks on the files it creates and we can
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // delete them.
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(NULL);
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(new TestingProfile());
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_->CreateBookmarkModel(true);
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_->CreateHistoryService(true, false);
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BlockTillBookmarkModelLoaded();
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TestNode bbn;
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PopulateNodeFromString(data[i].bbn_contents, &bbn);
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PopulateBookmarkNode(&bbn, bb_model_, bb_model_->GetBookmarkBarNode());
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TestNode other;
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PopulateNodeFromString(data[i].other_contents, &other);
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PopulateBookmarkNode(&other, bb_model_, bb_model_->other_node());
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_->CreateBookmarkModel(false);
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BlockTillBookmarkModelLoaded();
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VerifyModelMatchesNode(&bbn, bb_model_->GetBookmarkBarNode());
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VerifyModelMatchesNode(&other, bb_model_->other_node());
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VerifyNoDuplicateIDs(bb_model_);
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test class that creates a BookmarkModel with a real history backend.
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass BookmarkModelTestWithProfile2 : public BookmarkModelTestWithProfile {
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void SetUp() {
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    profile_.reset(new TestingProfile());
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Verifies the state of the model matches that of the state in the saved
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // history file.
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void VerifyExpectedState() {
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Here's the structure we expect:
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // bbn
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   www.google.com - Google
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   F1
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //     http://www.google.com/intl/en/ads/ - Google Advertising
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //     F11
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //       http://www.google.com/services/ - Google Business Solutions
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // other
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   OF1
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    //   http://www.google.com/intl/en/about.html - About Google
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* bbn = bb_model_->GetBookmarkBarNode();
821ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(2, bbn->child_count());
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* child = bbn->GetChild(0);
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(BookmarkNode::URL, child->type());
8253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("Google"), child->GetTitle());
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com"));
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = bbn->GetChild(1);
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->is_folder());
8303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("F1"), child->GetTitle());
831ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(2, child->child_count());
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const BookmarkNode* parent = child;
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = parent->GetChild(0);
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(BookmarkNode::URL, child->type());
8363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("Google Advertising"), child->GetTitle());
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/intl/en/ads/"));
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = parent->GetChild(1);
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->is_folder());
8413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("F11"), child->GetTitle());
842ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(1, child->child_count());
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent = child;
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = parent->GetChild(0);
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(BookmarkNode::URL, child->type());
8473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("Google Business Solutions"), child->GetTitle());
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->GetURL() == GURL("http://www.google.com/services/"));
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    parent = bb_model_->other_node();
851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(2, parent->child_count());
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = parent->GetChild(0);
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->is_folder());
8553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("OF1"), child->GetTitle());
856ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ASSERT_EQ(0, child->child_count());
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    child = parent->GetChild(1);
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_EQ(BookmarkNode::URL, child->type());
8603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    ASSERT_EQ(ASCIIToUTF16("About Google"), child->GetTitle());
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(child->GetURL() ==
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                GURL("http://www.google.com/intl/en/about.html"));
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(bb_model_->IsBookmarked(GURL("http://www.google.com")));
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void VerifyUniqueIDs() {
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::set<int64> ids;
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool has_unique = true;
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VerifyUniqueIDImpl(bb_model_->GetBookmarkBarNode(), &ids, &has_unique);
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    VerifyUniqueIDImpl(bb_model_->other_node(), &ids, &has_unique);
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ASSERT_TRUE(has_unique);
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void VerifyUniqueIDImpl(const BookmarkNode* node,
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          std::set<int64>* ids,
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          bool* has_unique) {
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!*has_unique)
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (ids->count(node->id()) != 0) {
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *has_unique = false;
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ids->insert(node->id());
886ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (int i = 0; i < node->child_count(); ++i) {
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      VerifyUniqueIDImpl(node->GetChild(i), ids, has_unique);
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!*has_unique)
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Tests migrating bookmarks from db into file. This copies an old history db
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// file containing bookmarks and make sure they are loaded correctly and
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// persisted correctly.
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTestWithProfile2, MigrateFromDBToFileTest) {
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Copy db file over that contains starred table.
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath old_history_path;
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PathService::Get(chrome::DIR_TEST_DATA, &old_history_path);
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  old_history_path = old_history_path.AppendASCII("bookmarks");
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  old_history_path = old_history_path.AppendASCII("History_with_starred");
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath new_history_path = profile_->GetPath();
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_util::Delete(new_history_path, true);
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  file_util::CreateDirectory(new_history_path);
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath new_history_file = new_history_path.Append(
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      chrome::kHistoryFilename);
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(file_util::CopyFile(old_history_path, new_history_file));
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create the history service making sure it doesn't blow away the file we
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // just copied.
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateHistoryService(false, false);
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateBookmarkModel(true);
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlockTillBookmarkModelLoaded();
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we loaded OK.
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyExpectedState();
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasFatalFailure())
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure the ids are unique.
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyUniqueIDs();
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasFatalFailure())
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Create again. This time we shouldn't load from history at all.
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateBookmarkModel(false);
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlockTillBookmarkModelLoaded();
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we loaded OK.
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyExpectedState();
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasFatalFailure())
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyUniqueIDs();
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (HasFatalFailure())
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Recreate the history service (with a clean db). Do this just to make sure
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we're loading correctly from the bookmarks file.
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateHistoryService(true, false);
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateBookmarkModel(false);
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlockTillBookmarkModelLoaded();
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyExpectedState();
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  VerifyUniqueIDs();
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Simple test that removes a bookmark. This test exercises the code paths in
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// History that block till bookmark bar model is loaded.
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTestWithProfile2, RemoveNotification) {
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateHistoryService(false, false);
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->CreateBookmarkModel(true);
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BlockTillBookmarkModelLoaded();
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add a URL.
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url("http://www.google.com");
9573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bb_model_->SetURLStarred(url, string16(), true);
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->AddPage(
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url, NULL, 1, GURL(), PageTransition::TYPED,
9613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      history::RedirectList(), history::SOURCE_BROWSED, false);
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This won't actually delete the URL, rather it'll empty out the visits.
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This triggers blocking on the BookmarkModel.
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)->DeleteURL(url);
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(BookmarkModelTest, Sort) {
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'.
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // 'C' and 'a' are folders.
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestNode bbn;
9723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PopulateNodeFromString("B [ a ] d [ a ]", &bbn);
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BookmarkNode* parent = model.GetBookmarkBarNode();
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PopulateBookmarkNode(&bbn, &model, parent);
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* child1 = AsMutable(parent->GetChild(1));
977ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  child1->set_title(ASCIIToUTF16("a"));
978ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delete child1->Remove(child1->GetChild(0));
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BookmarkNode* child3 = AsMutable(parent->GetChild(3));
980ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  child3->set_title(ASCIIToUTF16("C"));
981ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delete child3->Remove(child3->GetChild(0));
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ClearCounts();
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sort the children of the bookmark bar node.
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  model.SortChildren(parent);
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure we were notified.
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AssertObserverCount(0, 0, 0, 0, 1);
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure the order matches (remember, 'a' and 'C' are folders and
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // come first).
9933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(parent->GetChild(0)->GetTitle(), ASCIIToUTF16("a"));
9943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(parent->GetChild(1)->GetTitle(), ASCIIToUTF16("C"));
9953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(parent->GetChild(2)->GetTitle(), ASCIIToUTF16("B"));
9963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EXPECT_EQ(parent->GetChild(3)->GetTitle(), ASCIIToUTF16("d"));
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
998