| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | |
| 8 | |
| 9 #include <string> | |
| 10 | |
| 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" | |
| 22 | |
| 23 using base::ASCIIToUTF16; | |
| 24 using base::UTF16ToUTF8; | |
| 25 using base::Time; | |
| 26 using base::TimeDelta; | |
| 27 using content::BrowserThread; | |
| 28 | |
| 29 // Base class for bookmark editor tests. This class is a copy from | |
| 30 // bookmark_editor_view_unittest.cc, and all the tests in this file are | |
| 31 // GTK-ifications of the corresponding views tests. Testing here is really | |
| 32 // important because on Linux, we make round trip copies from chrome's | |
| 33 // BookmarkModel class to GTK's native GtkTreeStore. | |
| 34 class BookmarkEditorGtkTest : public testing::Test { | |
| 35 public: | |
| 36 BookmarkEditorGtkTest() | |
| 37 : model_(NULL), | |
| 38 ui_thread_(BrowserThread::UI, &message_loop_), | |
| 39 file_thread_(BrowserThread::FILE, &message_loop_) { | |
| 40 } | |
| 41 | |
| 42 virtual void SetUp() OVERRIDE { | |
| 43 profile_.reset(new TestingProfile()); | |
| 44 profile_->CreateBookmarkModel(true); | |
| 45 | |
| 46 model_ = BookmarkModelFactory::GetForProfile(profile_.get()); | |
| 47 test::WaitForBookmarkModelToLoad(model_); | |
| 48 | |
| 49 AddTestData(); | |
| 50 } | |
| 51 | |
| 52 virtual void TearDown() OVERRIDE { | |
| 53 } | |
| 54 | |
| 55 protected: | |
| 56 std::string base_path() const { return "file:///c:/tmp/"; } | |
| 57 | |
| 58 const BookmarkNode* GetNode(const std::string& name) { | |
| 59 return model_->GetMostRecentlyAddedNodeForURL(GURL(base_path() + name)); | |
| 60 } | |
| 61 | |
| 62 BookmarkModel* model_; | |
| 63 scoped_ptr<TestingProfile> profile_; | |
| 64 | |
| 65 private: | |
| 66 // Creates the following structure: | |
| 67 // bookmark bar node | |
| 68 // a | |
| 69 // F1 | |
| 70 // f1a | |
| 71 // F11 | |
| 72 // f11a | |
| 73 // F2 | |
| 74 // other node | |
| 75 // oa | |
| 76 // OF1 | |
| 77 // of1a | |
| 78 // mobile node | |
| 79 // sa | |
| 80 void AddTestData() { | |
| 81 std::string test_base = base_path(); | |
| 82 | |
| 83 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("a"), | |
| 84 GURL(test_base + "a")); | |
| 85 const BookmarkNode* f1 = | |
| 86 model_->AddFolder(model_->bookmark_bar_node(), 1, ASCIIToUTF16("F1")); | |
| 87 model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a")); | |
| 88 const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11")); | |
| 89 model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a")); | |
| 90 model_->AddFolder(model_->bookmark_bar_node(), 2, ASCIIToUTF16("F2")); | |
| 91 | |
| 92 // Children of the other node. | |
| 93 model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"), | |
| 94 GURL(test_base + "oa")); | |
| 95 const BookmarkNode* of1 = | |
| 96 model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1")); | |
| 97 model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a")); | |
| 98 | |
| 99 // Children of the mobile node. | |
| 100 model_->AddURL(model_->mobile_node(), 0, ASCIIToUTF16("sa"), | |
| 101 GURL(test_base + "sa")); | |
| 102 } | |
| 103 | |
| 104 base::MessageLoopForUI message_loop_; | |
| 105 content::TestBrowserThread ui_thread_; | |
| 106 content::TestBrowserThread file_thread_; | |
| 107 }; | |
| 108 | |
| 109 // Makes sure the tree model matches that of the bookmark bar model. | |
| 110 TEST_F(BookmarkEditorGtkTest, ModelsMatch) { | |
| 111 BookmarkEditorGtk editor( | |
| 112 NULL, | |
| 113 profile_.get(), | |
| 114 NULL, | |
| 115 BookmarkEditor::EditDetails::AddNodeInFolder( | |
| 116 NULL, -1, GURL(), base::string16()), | |
| 117 BookmarkEditor::SHOW_TREE); | |
| 118 | |
| 119 // The root should have two or three children, one for the bookmark bar node, | |
| 120 // another for the 'other bookmarks' folder, and depending on the visib | |
| 121 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 122 GtkTreeIter toplevel; | |
| 123 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &toplevel)); | |
| 124 GtkTreeIter bookmark_bar_node = toplevel; | |
| 125 ASSERT_TRUE(gtk_tree_model_iter_next(store, &toplevel)); | |
| 126 GtkTreeIter other_node = toplevel; | |
| 127 if (model_->mobile_node()->IsVisible()) { | |
| 128 // If we have a mobile node, then the iterator should find one element after | |
| 129 // "other bookmarks" | |
| 130 ASSERT_TRUE(gtk_tree_model_iter_next(store, &toplevel)); | |
| 131 ASSERT_FALSE(gtk_tree_model_iter_next(store, &toplevel)); | |
| 132 } else { | |
| 133 ASSERT_FALSE(gtk_tree_model_iter_next(store, &toplevel)); | |
| 134 } | |
| 135 | |
| 136 // The bookmark bar should have 2 nodes: folder F1 and F2. | |
| 137 GtkTreeIter f1_iter; | |
| 138 GtkTreeIter child; | |
| 139 ASSERT_EQ(2, gtk_tree_model_iter_n_children(store, &bookmark_bar_node)); | |
| 140 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &bookmark_bar_node)); | |
| 141 f1_iter = child; | |
| 142 ASSERT_EQ("F1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child))); | |
| 143 ASSERT_TRUE(gtk_tree_model_iter_next(store, &child)); | |
| 144 ASSERT_EQ("F2", UTF16ToUTF8(GetTitleFromTreeIter(store, &child))); | |
| 145 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child)); | |
| 146 | |
| 147 // F1 should have one child, F11 | |
| 148 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f1_iter)); | |
| 149 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &f1_iter)); | |
| 150 ASSERT_EQ("F11", UTF16ToUTF8(GetTitleFromTreeIter(store, &child))); | |
| 151 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child)); | |
| 152 | |
| 153 // Other node should have one child (OF1). | |
| 154 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &other_node)); | |
| 155 ASSERT_TRUE(gtk_tree_model_iter_children(store, &child, &other_node)); | |
| 156 ASSERT_EQ("OF1", UTF16ToUTF8(GetTitleFromTreeIter(store, &child))); | |
| 157 ASSERT_FALSE(gtk_tree_model_iter_next(store, &child)); | |
| 158 } | |
| 159 | |
| 160 // Changes the title and makes sure parent/visual order doesn't change. | |
| 161 TEST_F(BookmarkEditorGtkTest, EditTitleKeepsPosition) { | |
| 162 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 163 BookmarkEditor::EditDetails::EditNode(GetNode("a")), | |
| 164 BookmarkEditor::SHOW_TREE); | |
| 165 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a"); | |
| 166 | |
| 167 GtkTreeIter bookmark_bar_node; | |
| 168 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 169 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node)); | |
| 170 editor.ApplyEdits(&bookmark_bar_node); | |
| 171 | |
| 172 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
| 173 ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle()); | |
| 174 // The URL shouldn't have changed. | |
| 175 ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->url()); | |
| 176 } | |
| 177 | |
| 178 // Changes the url and makes sure parent/visual order doesn't change. | |
| 179 TEST_F(BookmarkEditorGtkTest, EditURLKeepsPosition) { | |
| 180 Time node_time = GetNode("a")->date_added(); | |
| 181 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 182 BookmarkEditor::EditDetails::EditNode(GetNode("a")), | |
| 183 BookmarkEditor::SHOW_TREE); | |
| 184 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_), | |
| 185 GURL(base_path() + "new_a").spec().c_str()); | |
| 186 | |
| 187 GtkTreeIter bookmark_bar_node; | |
| 188 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 189 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node)); | |
| 190 editor.ApplyEdits(&bookmark_bar_node); | |
| 191 | |
| 192 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
| 193 ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle()); | |
| 194 // The URL should have changed. | |
| 195 ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->url()); | |
| 196 ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added()); | |
| 197 } | |
| 198 | |
| 199 // Moves 'a' to be a child of the other node. | |
| 200 TEST_F(BookmarkEditorGtkTest, ChangeParent) { | |
| 201 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 202 BookmarkEditor::EditDetails::EditNode(GetNode("a")), | |
| 203 BookmarkEditor::SHOW_TREE); | |
| 204 | |
| 205 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 206 GtkTreeIter gtk_other_node; | |
| 207 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, >k_other_node)); | |
| 208 ASSERT_TRUE(gtk_tree_model_iter_next(store, >k_other_node)); | |
| 209 editor.ApplyEdits(>k_other_node); | |
| 210 | |
| 211 const BookmarkNode* other_node = model_->other_node(); | |
| 212 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle()); | |
| 213 ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->url()); | |
| 214 } | |
| 215 | |
| 216 // Moves 'a' to be a child of the other node. | |
| 217 // Moves 'a' to be a child of the other node and changes its url to new_a. | |
| 218 TEST_F(BookmarkEditorGtkTest, ChangeParentAndURL) { | |
| 219 Time node_time = GetNode("a")->date_added(); | |
| 220 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 221 BookmarkEditor::EditDetails::EditNode(GetNode("a")), | |
| 222 BookmarkEditor::SHOW_TREE); | |
| 223 | |
| 224 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_), | |
| 225 GURL(base_path() + "new_a").spec().c_str()); | |
| 226 | |
| 227 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 228 GtkTreeIter gtk_other_node; | |
| 229 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, >k_other_node)); | |
| 230 ASSERT_TRUE(gtk_tree_model_iter_next(store, >k_other_node)); | |
| 231 editor.ApplyEdits(>k_other_node); | |
| 232 | |
| 233 const BookmarkNode* other_node = model_->other_node(); | |
| 234 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle()); | |
| 235 ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->url()); | |
| 236 ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added()); | |
| 237 } | |
| 238 | |
| 239 // Creates a new folder and moves a node to it. | |
| 240 TEST_F(BookmarkEditorGtkTest, MoveToNewParent) { | |
| 241 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 242 BookmarkEditor::EditDetails::EditNode(GetNode("a")), | |
| 243 BookmarkEditor::SHOW_TREE); | |
| 244 | |
| 245 GtkTreeIter bookmark_bar_node; | |
| 246 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 247 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node)); | |
| 248 | |
| 249 // The bookmark bar should have 2 nodes: folder F1 and F2. | |
| 250 GtkTreeIter f2_iter; | |
| 251 ASSERT_EQ(2, gtk_tree_model_iter_n_children(store, &bookmark_bar_node)); | |
| 252 ASSERT_TRUE(gtk_tree_model_iter_children(store, &f2_iter, | |
| 253 &bookmark_bar_node)); | |
| 254 ASSERT_TRUE(gtk_tree_model_iter_next(store, &f2_iter)); | |
| 255 | |
| 256 // Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21". | |
| 257 GtkTreeIter f21_iter; | |
| 258 editor.AddNewFolder(&f2_iter, &f21_iter); | |
| 259 gtk_tree_store_set(editor.tree_store_, &f21_iter, FOLDER_NAME, "F21", -1); | |
| 260 GtkTreeIter f211_iter; | |
| 261 editor.AddNewFolder(&f21_iter, &f211_iter); | |
| 262 gtk_tree_store_set(editor.tree_store_, &f211_iter, FOLDER_NAME, "F211", -1); | |
| 263 | |
| 264 ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f2_iter)); | |
| 265 | |
| 266 editor.ApplyEdits(&f2_iter); | |
| 267 | |
| 268 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
| 269 const BookmarkNode* mf2 = bb_node->GetChild(1); | |
| 270 | |
| 271 // F2 in the model should have two children now: F21 and the node edited. | |
| 272 ASSERT_EQ(2, mf2->child_count()); | |
| 273 // F21 should be first. | |
| 274 ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle()); | |
| 275 // Then a. | |
| 276 ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle()); | |
| 277 | |
| 278 // F21 should have one child, F211. | |
| 279 const BookmarkNode* mf21 = mf2->GetChild(0); | |
| 280 ASSERT_EQ(1, mf21->child_count()); | |
| 281 ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle()); | |
| 282 } | |
| 283 | |
| 284 // Brings up the editor, creating a new URL on the bookmark bar. | |
| 285 TEST_F(BookmarkEditorGtkTest, NewURL) { | |
| 286 BookmarkEditorGtk editor( | |
| 287 NULL, | |
| 288 profile_.get(), | |
| 289 NULL, | |
| 290 BookmarkEditor::EditDetails::AddNodeInFolder( | |
| 291 NULL, -1, GURL(), base::string16()), | |
| 292 BookmarkEditor::SHOW_TREE); | |
| 293 | |
| 294 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_), | |
| 295 GURL(base_path() + "a").spec().c_str()); | |
| 296 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a"); | |
| 297 | |
| 298 GtkTreeIter bookmark_bar_node; | |
| 299 GtkTreeModel* store = GTK_TREE_MODEL(editor.tree_store_); | |
| 300 ASSERT_TRUE(gtk_tree_model_get_iter_first(store, &bookmark_bar_node)); | |
| 301 editor.ApplyEdits(&bookmark_bar_node); | |
| 302 | |
| 303 const BookmarkNode* bb_node = model_->bookmark_bar_node(); | |
| 304 ASSERT_EQ(4, bb_node->child_count()); | |
| 305 | |
| 306 const BookmarkNode* new_node = bb_node->GetChild(3); | |
| 307 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); | |
| 308 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url()); | |
| 309 } | |
| 310 | |
| 311 // Brings up the editor with no tree and modifies the url. | |
| 312 TEST_F(BookmarkEditorGtkTest, ChangeURLNoTree) { | |
| 313 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 314 BookmarkEditor::EditDetails::EditNode( | |
| 315 model_->other_node()->GetChild(0)), | |
| 316 BookmarkEditor::NO_TREE); | |
| 317 | |
| 318 gtk_entry_set_text(GTK_ENTRY(editor.url_entry_), | |
| 319 GURL(base_path() + "a").spec().c_str()); | |
| 320 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a"); | |
| 321 | |
| 322 editor.ApplyEdits(NULL); | |
| 323 | |
| 324 const BookmarkNode* other_node = model_->other_node(); | |
| 325 ASSERT_EQ(2, other_node->child_count()); | |
| 326 | |
| 327 const BookmarkNode* new_node = other_node->GetChild(0); | |
| 328 | |
| 329 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); | |
| 330 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url()); | |
| 331 } | |
| 332 | |
| 333 // Brings up the editor with no tree and modifies only the title. | |
| 334 TEST_F(BookmarkEditorGtkTest, ChangeTitleNoTree) { | |
| 335 BookmarkEditorGtk editor(NULL, profile_.get(), NULL, | |
| 336 BookmarkEditor::EditDetails::EditNode( | |
| 337 model_->other_node()->GetChild(0)), | |
| 338 BookmarkEditor::NO_TREE); | |
| 339 gtk_entry_set_text(GTK_ENTRY(editor.name_entry_), "new_a"); | |
| 340 | |
| 341 editor.ApplyEdits(); | |
| 342 | |
| 343 const BookmarkNode* other_node = model_->other_node(); | |
| 344 ASSERT_EQ(2, other_node->child_count()); | |
| 345 | |
| 346 const BookmarkNode* new_node = other_node->GetChild(0); | |
| 347 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); | |
| 348 } | |
| OLD | NEW |