1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h"
11 #include "base/compiler_specific.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/bookmarks/bookmark_model.h"
16 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
17 #include "chrome/browser/bookmarks/bookmark_test_helpers.h"
18 #include "chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h"
19 #include "chrome/test/base/testing_profile.h"
20 #include "content/public/test/test_browser_thread.h"
21 #include "testing/gtest/include/gtest/gtest.h"
24 using base::TimeDelta;
25 using content::BrowserThread;
27 // Base class for bookmark editor tests. This class is a copy from
28 // bookmark_editor_view_unittest.cc, and all the tests in this file are
29 // GTK-ifications of the corresponding views tests. Testing here is really
30 // important because on Linux, we make round trip copies from chrome's
31 // BookmarkModel class to GTK's native GtkTreeStore.
32 class BookmarkEditorGtkTest : public testing::Test {
34 BookmarkEditorGtkTest()
36 ui_thread_(BrowserThread::UI, &message_loop_),
37 file_thread_(BrowserThread::FILE, &message_loop_) {
40 virtual void SetUp() OVERRIDE {
41 profile_.reset(new TestingProfile());
42 profile_->CreateBookmarkModel(true);
44 model_ = BookmarkModelFactory::GetForProfile(profile_.get());
45 test::WaitForBookmarkModelToLoad(model_);
50 virtual void TearDown() OVERRIDE {
54 std::string base_path() const { return "file:///c:/tmp/"; }
56 const BookmarkNode* GetNode(const std::string& name) {
57 return model_->GetMostRecentlyAddedNodeForURL(GURL(base_path() + name));
60 BookmarkModel* model_;
61 scoped_ptr<TestingProfile> profile_;
64 // Creates the following structure:
79 std::string test_base = base_path();
81 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("a"),
82 GURL(test_base + "a"));
83 const BookmarkNode* f1 =
84 model_->AddFolder(model_->bookmark_bar_node(), 1, ASCIIToUTF16("F1"));
85 model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
86 const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
87 model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
88 model_->AddFolder(model_->bookmark_bar_node(), 2, ASCIIToUTF16("F2"));
90 // Children of the other node.
91 model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
92 GURL(test_base + "oa"));
93 const BookmarkNode* of1 =
94 model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1"));
95 model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
97 // Children of the mobile node.
98 model_->AddURL(model_->mobile_node(), 0, ASCIIToUTF16("sa"),
99 GURL(test_base + "sa"));
102 base::MessageLoopForUI message_loop_;
103 content::TestBrowserThread ui_thread_;
104 content::TestBrowserThread file_thread_;
107 // Makes sure the tree model matches that of the bookmark bar model.
108 TEST_F(BookmarkEditorGtkTest, ModelsMatch) {
109 BookmarkEditorGtk editor(
113 BookmarkEditor::EditDetails::AddNodeInFolder(
114 NULL, -1, GURL(), string16()),
115 BookmarkEditor::SHOW_TREE);
117 // The root should have two or three children, one for the bookmark bar node,
118 // another for the 'other bookmarks' folder, and depending on the visib
119 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
120 GtkTreeIter toplevel;
121 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &toplevel));
122 GtkTreeIter bookmark_bar_node = toplevel;
123 ASSERT_TRUE(gtk_tree_model_iter_next(store, &toplevel));
124 GtkTreeIter other_node = toplevel;
125 if (model_->mobile_node()->IsVisible()) {
126 // If we have a mobile node, then the iterator should find one element after
128 ASSERT_TRUE(gtk_tree_model_iter_next(store, &toplevel));
129 ASSERT_FALSE(gtk_tree_model_iter_next(store, &toplevel));
131 ASSERT_FALSE(gtk_tree_model_iter_next(store, &toplevel));
134 // The bookmark bar should have 2 nodes: folder F1 and F2.
137 ASSERT_EQ(2, gtk_tree_model_iter_n_children(store, &bookmark_bar_node));
138 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &bookmark_bar_node));
140 ASSERT_EQ("F1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
141 ASSERT_TRUE(gtk_tree_model_iter_next(store, &child));
142 ASSERT_EQ("F2", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
143 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
145 // F1 should have one child, F11
146 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f1_iter));
147 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &f1_iter));
148 ASSERT_EQ("F11", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
149 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
151 // Other node should have one child (OF1).
152 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &other_node));
153 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &other_node));
154 ASSERT_EQ("OF1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child)));
155 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child));
158 // Changes the title and makes sure parent/visual order doesn't change.
159 TEST_F(BookmarkEditorGtkTest, EditTitleKeepsPosition) {
160 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
161 BookmarkEditor::EditDetails::EditNode(GetNode("a")),
162 BookmarkEditor::SHOW_TREE);
163 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a");
165 GtkTreeIter bookmark_bar_node;
166 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
167 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node));
168 editor.ApplyEdits(&bookmark_bar_node);
170 const BookmarkNode* bb_node = model_->bookmark_bar_node();
171 ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle());
172 // The URL shouldn't have changed.
173 ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->url());
176 // Changes the url and makes sure parent/visual order doesn't change.
177 TEST_F(BookmarkEditorGtkTest, EditURLKeepsPosition) {
178 Time node_time = GetNode("a")->date_added();
179 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
180 BookmarkEditor::EditDetails::EditNode(GetNode("a")),
181 BookmarkEditor::SHOW_TREE);
182 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_),
183 GURL(base_path() + "new_a").spec().c_str());
185 GtkTreeIter bookmark_bar_node;
186 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
187 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node));
188 editor.ApplyEdits(&bookmark_bar_node);
190 const BookmarkNode* bb_node = model_->bookmark_bar_node();
191 ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle());
192 // The URL should have changed.
193 ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->url());
194 ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added());
197 // Moves 'a' to be a child of the other node.
198 TEST_F(BookmarkEditorGtkTest, ChangeParent) {
199 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
200 BookmarkEditor::EditDetails::EditNode(GetNode("a")),
201 BookmarkEditor::SHOW_TREE);
203 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
204 GtkTreeIter gtk_other_node;
205 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, >k_other_node));
206 ASSERT_TRUE(gtk_tree_model_iter_next(store, >k_other_node));
207 editor.ApplyEdits(>k_other_node);
209 const BookmarkNode* other_node = model_->other_node();
210 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
211 ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->url());
214 // Moves 'a' to be a child of the other node.
215 // Moves 'a' to be a child of the other node and changes its url to new_a.
216 TEST_F(BookmarkEditorGtkTest, ChangeParentAndURL) {
217 Time node_time = GetNode("a")->date_added();
218 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
219 BookmarkEditor::EditDetails::EditNode(GetNode("a")),
220 BookmarkEditor::SHOW_TREE);
222 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_),
223 GURL(base_path() + "new_a").spec().c_str());
225 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
226 GtkTreeIter gtk_other_node;
227 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, >k_other_node));
228 ASSERT_TRUE(gtk_tree_model_iter_next(store, >k_other_node));
229 editor.ApplyEdits(>k_other_node);
231 const BookmarkNode* other_node = model_->other_node();
232 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
233 ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->url());
234 ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added());
237 // Creates a new folder and moves a node to it.
238 TEST_F(BookmarkEditorGtkTest, MoveToNewParent) {
239 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
240 BookmarkEditor::EditDetails::EditNode(GetNode("a")),
241 BookmarkEditor::SHOW_TREE);
243 GtkTreeIter bookmark_bar_node;
244 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
245 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node));
247 // The bookmark bar should have 2 nodes: folder F1 and F2.
249 ASSERT_EQ(2, gtk_tree_model_iter_n_children(store, &bookmark_bar_node));
250 ASSERT_TRUE(gtk_tree_model_iter_children(store, &f2_iter,
251 &bookmark_bar_node));
252 ASSERT_TRUE(gtk_tree_model_iter_next(store, &f2_iter));
254 // Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21".
255 GtkTreeIter f21_iter;
256 editor.AddNewFolder(&f2_iter, &f21_iter);
257 gtk_tree_store_set(editor.tree_store_, &f21_iter, FOLDER_NAME, "F21", -1);
258 GtkTreeIter f211_iter;
259 editor.AddNewFolder(&f21_iter, &f211_iter);
260 gtk_tree_store_set(editor.tree_store_, &f211_iter, FOLDER_NAME, "F211", -1);
262 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f2_iter));
264 editor.ApplyEdits(&f2_iter);
266 const BookmarkNode* bb_node = model_->bookmark_bar_node();
267 const BookmarkNode* mf2 = bb_node->GetChild(1);
269 // F2 in the model should have two children now: F21 and the node edited.
270 ASSERT_EQ(2, mf2->child_count());
271 // F21 should be first.
272 ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle());
274 ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle());
276 // F21 should have one child, F211.
277 const BookmarkNode* mf21 = mf2->GetChild(0);
278 ASSERT_EQ(1, mf21->child_count());
279 ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle());
282 // Brings up the editor, creating a new URL on the bookmark bar.
283 TEST_F(BookmarkEditorGtkTest, NewURL) {
284 BookmarkEditorGtk editor(
288 BookmarkEditor::EditDetails::AddNodeInFolder(
289 NULL, -1, GURL(), string16()),
290 BookmarkEditor::SHOW_TREE);
292 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_),
293 GURL(base_path() + "a").spec().c_str());
294 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a");
296 GtkTreeIter bookmark_bar_node;
297 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_);
298 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node));
299 editor.ApplyEdits(&bookmark_bar_node);
301 const BookmarkNode* bb_node = model_->bookmark_bar_node();
302 ASSERT_EQ(4, bb_node->child_count());
304 const BookmarkNode* new_node = bb_node->GetChild(3);
305 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
306 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url());
309 // Brings up the editor with no tree and modifies the url.
310 TEST_F(BookmarkEditorGtkTest, ChangeURLNoTree) {
311 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
312 BookmarkEditor::EditDetails::EditNode(
313 model_->other_node()->GetChild(0)),
314 BookmarkEditor::NO_TREE);
316 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_),
317 GURL(base_path() + "a").spec().c_str());
318 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a");
320 editor.ApplyEdits(NULL);
322 const BookmarkNode* other_node = model_->other_node();
323 ASSERT_EQ(2, other_node->child_count());
325 const BookmarkNode* new_node = other_node->GetChild(0);
327 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
328 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url());
331 // Brings up the editor with no tree and modifies only the title.
332 TEST_F(BookmarkEditorGtkTest, ChangeTitleNoTree) {
333 BookmarkEditorGtk editor(NULL, profile_.get(), NULL,
334 BookmarkEditor::EditDetails::EditNode(
335 model_->other_node()->GetChild(0)),
336 BookmarkEditor::NO_TREE);
337 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a");
341 const BookmarkNode* other_node = model_->other_node();
342 ASSERT_EQ(2, other_node->child_count());
344 const BookmarkNode* new_node = other_node->GetChild(0);
345 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());