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