bookmark_editor_view_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/views/bookmarks/bookmark_editor_view.h" 6 7#include <string> 8 9#include "base/message_loop/message_loop.h" 10#include "base/strings/string_util.h" 11#include "base/strings/utf_string_conversions.h" 12#include "chrome/browser/bookmarks/bookmark_model.h" 13#include "chrome/browser/bookmarks/bookmark_model_factory.h" 14#include "chrome/browser/bookmarks/bookmark_test_helpers.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/test/base/testing_profile.h" 17#include "content/public/test/test_browser_thread.h" 18#include "testing/gtest/include/gtest/gtest.h" 19#include "ui/views/controls/textfield/textfield.h" 20#include "ui/views/controls/tree/tree_view.h" 21 22using base::ASCIIToUTF16; 23using base::Time; 24using base::TimeDelta; 25using content::BrowserThread; 26 27// Base class for bookmark editor tests. Creates a BookmarkModel and populates 28// it with test data. 29class BookmarkEditorViewTest : public testing::Test { 30 public: 31 BookmarkEditorViewTest() 32 : ui_thread_(BrowserThread::UI, &message_loop_), 33 file_thread_(BrowserThread::FILE, &message_loop_), 34 model_(NULL) { 35 } 36 37 virtual void SetUp() { 38 profile_.reset(new TestingProfile()); 39 profile_->CreateBookmarkModel(true); 40 41 model_ = BookmarkModelFactory::GetForProfile(profile_.get()); 42 test::WaitForBookmarkModelToLoad(model_); 43 44 AddTestData(); 45 } 46 47 virtual void TearDown() { 48 } 49 50 protected: 51 std::string base_path() const { return "file:///c:/tmp/"; } 52 53 const BookmarkNode* GetNode(const std::string& name) { 54 return model_->GetMostRecentlyAddedNodeForURL(GURL(base_path() + name)); 55 } 56 57 BookmarkNode* GetMutableNode(const std::string& name) { 58 return const_cast<BookmarkNode*>(GetNode(name)); 59 } 60 61 BookmarkEditorView::EditorTreeModel* editor_tree_model() { 62 return editor_->tree_model_.get(); 63 } 64 65 void CreateEditor(Profile* profile, 66 const BookmarkNode* parent, 67 const BookmarkEditor::EditDetails& details, 68 BookmarkEditor::Configuration configuration) { 69 editor_.reset(new BookmarkEditorView(profile, parent, details, 70 configuration)); 71 } 72 73 void SetTitleText(const base::string16& title) { 74 editor_->title_tf_->SetText(title); 75 } 76 77 void SetURLText(const base::string16& text) { 78 if (editor_->details_.type != BookmarkEditor::EditDetails::NEW_FOLDER) 79 editor_->url_tf_->SetText(text); 80 } 81 82 void ApplyEdits() { 83 editor_->ApplyEdits(); 84 } 85 86 void ApplyEdits(BookmarkEditorView::EditorNode* node) { 87 editor_->ApplyEdits(node); 88 } 89 90 BookmarkEditorView::EditorNode* AddNewFolder( 91 BookmarkEditorView::EditorNode* parent) { 92 return editor_->AddNewFolder(parent); 93 } 94 95 void NewFolder() { 96 return editor_->NewFolder(); 97 } 98 99 bool URLTFHasParent() { 100 if (editor_->details_.type == BookmarkEditor::EditDetails::NEW_FOLDER) 101 return false; 102 return editor_->url_tf_->parent(); 103 } 104 105 void ExpandAndSelect() { 106 editor_->ExpandAndSelect(); 107 } 108 109 views::TreeView* tree_view() { return editor_->tree_view_; } 110 111 base::MessageLoopForUI message_loop_; 112 content::TestBrowserThread ui_thread_; 113 content::TestBrowserThread file_thread_; 114 115 BookmarkModel* model_; 116 scoped_ptr<TestingProfile> profile_; 117 118 private: 119 // Creates the following structure: 120 // bookmark bar node 121 // a 122 // F1 123 // f1a 124 // F11 125 // f11a 126 // F2 127 // other node 128 // oa 129 // OF1 130 // of1a 131 void AddTestData() { 132 const BookmarkNode* bb_node = model_->bookmark_bar_node(); 133 std::string test_base = base_path(); 134 model_->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a")); 135 const BookmarkNode* f1 = model_->AddFolder(bb_node, 1, ASCIIToUTF16("F1")); 136 model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a")); 137 const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11")); 138 model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a")); 139 model_->AddFolder(bb_node, 2, ASCIIToUTF16("F2")); 140 141 // Children of the other node. 142 model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"), 143 GURL(test_base + "oa")); 144 const BookmarkNode* of1 = 145 model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1")); 146 model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a")); 147 } 148 149 scoped_ptr<BookmarkEditorView> editor_; 150}; 151 152// Makes sure the tree model matches that of the bookmark bar model. 153TEST_F(BookmarkEditorViewTest, ModelsMatch) { 154 CreateEditor(profile_.get(), NULL, 155 BookmarkEditor::EditDetails::AddNodeInFolder( 156 NULL, -1, GURL(), base::string16()), 157 BookmarkEditorView::SHOW_TREE); 158 BookmarkEditorView::EditorNode* editor_root = editor_tree_model()->GetRoot(); 159 // The root should have two or three children: bookmark bar, other bookmarks 160 // and conditionally mobile bookmarks. 161 if (model_->mobile_node()->IsVisible()) { 162 ASSERT_EQ(3, editor_root->child_count()); 163 } else { 164 ASSERT_EQ(2, editor_root->child_count()); 165 } 166 167 BookmarkEditorView::EditorNode* bb_node = editor_root->GetChild(0); 168 // The root should have 2 nodes: folder F1 and F2. 169 ASSERT_EQ(2, bb_node->child_count()); 170 ASSERT_EQ(ASCIIToUTF16("F1"), bb_node->GetChild(0)->GetTitle()); 171 ASSERT_EQ(ASCIIToUTF16("F2"), bb_node->GetChild(1)->GetTitle()); 172 173 // F1 should have one child, F11 174 ASSERT_EQ(1, bb_node->GetChild(0)->child_count()); 175 ASSERT_EQ(ASCIIToUTF16("F11"), bb_node->GetChild(0)->GetChild(0)->GetTitle()); 176 177 BookmarkEditorView::EditorNode* other_node = editor_root->GetChild(1); 178 // Other node should have one child (OF1). 179 ASSERT_EQ(1, other_node->child_count()); 180 ASSERT_EQ(ASCIIToUTF16("OF1"), other_node->GetChild(0)->GetTitle()); 181} 182 183// Changes the title and makes sure parent/visual order doesn't change. 184TEST_F(BookmarkEditorViewTest, EditTitleKeepsPosition) { 185 CreateEditor(profile_.get(), NULL, 186 BookmarkEditor::EditDetails::EditNode(GetNode("a")), 187 BookmarkEditorView::SHOW_TREE); 188 SetTitleText(L"new_a"); 189 190 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0)); 191 192 const BookmarkNode* bb_node = 193 BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node(); 194 ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle()); 195 // The URL shouldn't have changed. 196 ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->url()); 197} 198 199// Changes the url and makes sure parent/visual order doesn't change. 200TEST_F(BookmarkEditorViewTest, EditURLKeepsPosition) { 201 Time node_time = Time::Now() + TimeDelta::FromDays(2); 202 GetMutableNode("a")->set_date_added(node_time); 203 CreateEditor(profile_.get(), NULL, 204 BookmarkEditor::EditDetails::EditNode(GetNode("a")), 205 BookmarkEditorView::SHOW_TREE); 206 207 SetURLText(base::UTF8ToWide(GURL(base_path() + "new_a").spec())); 208 209 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0)); 210 211 const BookmarkNode* bb_node = 212 BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node(); 213 ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle()); 214 // The URL should have changed. 215 ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->url()); 216 ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added()); 217} 218 219// Moves 'a' to be a child of the other node. 220TEST_F(BookmarkEditorViewTest, ChangeParent) { 221 CreateEditor(profile_.get(), NULL, 222 BookmarkEditor::EditDetails::EditNode(GetNode("a")), 223 BookmarkEditorView::SHOW_TREE); 224 225 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1)); 226 227 const BookmarkNode* other_node = 228 BookmarkModelFactory::GetForProfile(profile_.get())->other_node(); 229 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle()); 230 ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->url()); 231} 232 233// Moves 'a' to be a child of the other node and changes its url to new_a. 234TEST_F(BookmarkEditorViewTest, ChangeParentAndURL) { 235 Time node_time = Time::Now() + TimeDelta::FromDays(2); 236 GetMutableNode("a")->set_date_added(node_time); 237 CreateEditor(profile_.get(), NULL, 238 BookmarkEditor::EditDetails::EditNode(GetNode("a")), 239 BookmarkEditorView::SHOW_TREE); 240 241 SetURLText(base::UTF8ToWide(GURL(base_path() + "new_a").spec())); 242 243 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1)); 244 245 const BookmarkNode* other_node = 246 BookmarkModelFactory::GetForProfile(profile_.get())->other_node(); 247 ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle()); 248 ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->url()); 249 ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added()); 250} 251 252// Creates a new folder and moves a node to it. 253TEST_F(BookmarkEditorViewTest, MoveToNewParent) { 254 CreateEditor(profile_.get(), NULL, 255 BookmarkEditor::EditDetails::EditNode(GetNode("a")), 256 BookmarkEditorView::SHOW_TREE); 257 258 // Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21". 259 BookmarkEditorView::EditorNode* f2 = 260 editor_tree_model()->GetRoot()->GetChild(0)->GetChild(1); 261 BookmarkEditorView::EditorNode* f21 = AddNewFolder(f2); 262 f21->SetTitle(ASCIIToUTF16("F21")); 263 BookmarkEditorView::EditorNode* f211 = AddNewFolder(f21); 264 f211->SetTitle(ASCIIToUTF16("F211")); 265 266 // Parent the node to "F21". 267 ApplyEdits(f2); 268 269 const BookmarkNode* bb_node = 270 BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node(); 271 const BookmarkNode* mf2 = bb_node->GetChild(1); 272 273 // F2 in the model should have two children now: F21 and the node edited. 274 ASSERT_EQ(2, mf2->child_count()); 275 // F21 should be first. 276 ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle()); 277 // Then a. 278 ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle()); 279 280 // F21 should have one child, F211. 281 const BookmarkNode* mf21 = mf2->GetChild(0); 282 ASSERT_EQ(1, mf21->child_count()); 283 ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle()); 284} 285 286// Brings up the editor, creating a new URL on the bookmark bar. 287TEST_F(BookmarkEditorViewTest, NewURL) { 288 const BookmarkNode* bb_node = 289 BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node(); 290 291 CreateEditor(profile_.get(), bb_node, 292 BookmarkEditor::EditDetails::AddNodeInFolder( 293 bb_node, 1, GURL(), base::string16()), 294 BookmarkEditorView::SHOW_TREE); 295 296 SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec())); 297 SetTitleText(L"new_a"); 298 299 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0)); 300 301 ASSERT_EQ(4, bb_node->child_count()); 302 303 const BookmarkNode* new_node = bb_node->GetChild(1); 304 305 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); 306 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url()); 307} 308 309// Brings up the editor with no tree and modifies the url. 310TEST_F(BookmarkEditorViewTest, ChangeURLNoTree) { 311 CreateEditor(profile_.get(), NULL, 312 BookmarkEditor::EditDetails::EditNode( 313 model_->other_node()->GetChild(0)), 314 BookmarkEditorView::NO_TREE); 315 316 SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec())); 317 SetTitleText(L"new_a"); 318 319 ApplyEdits(NULL); 320 321 const BookmarkNode* other_node = 322 BookmarkModelFactory::GetForProfile(profile_.get())->other_node(); 323 ASSERT_EQ(2, other_node->child_count()); 324 325 const BookmarkNode* new_node = other_node->GetChild(0); 326 327 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); 328 EXPECT_TRUE(GURL(base_path() + "a") == new_node->url()); 329} 330 331// Brings up the editor with no tree and modifies only the title. 332TEST_F(BookmarkEditorViewTest, ChangeTitleNoTree) { 333 CreateEditor(profile_.get(), NULL, 334 BookmarkEditor::EditDetails::EditNode( 335 model_->other_node()->GetChild(0)), 336 BookmarkEditorView::NO_TREE); 337 338 SetTitleText(L"new_a"); 339 340 ApplyEdits(NULL); 341 342 const BookmarkNode* other_node = 343 BookmarkModelFactory::GetForProfile(profile_.get())->other_node(); 344 ASSERT_EQ(2, other_node->child_count()); 345 346 const BookmarkNode* new_node = other_node->GetChild(0); 347 348 EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle()); 349} 350 351// Creates a new folder. 352TEST_F(BookmarkEditorViewTest, NewFolder) { 353 const BookmarkNode* bb_node = model_->bookmark_bar_node(); 354 BookmarkEditor::EditDetails details = 355 BookmarkEditor::EditDetails::AddFolder(bb_node, 1); 356 details.urls.push_back(std::make_pair(GURL(base_path() + "x"), 357 ASCIIToUTF16("z"))); 358 CreateEditor(profile_.get(), bb_node, details, BookmarkEditorView::SHOW_TREE); 359 360 // The url field shouldn't be visible. 361 EXPECT_FALSE(URLTFHasParent()); 362 SetTitleText(L"new_F"); 363 364 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0)); 365 366 // Make sure the folder was created. 367 ASSERT_EQ(4, bb_node->child_count()); 368 const BookmarkNode* new_node = bb_node->GetChild(1); 369 EXPECT_EQ(BookmarkNode::FOLDER, new_node->type()); 370 EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle()); 371 // The node should have one child. 372 ASSERT_EQ(1, new_node->child_count()); 373 const BookmarkNode* new_child = new_node->GetChild(0); 374 // Make sure the child url/title match. 375 EXPECT_EQ(BookmarkNode::URL, new_child->type()); 376 EXPECT_EQ(details.urls[0].second, new_child->GetTitle()); 377 EXPECT_EQ(details.urls[0].first, new_child->url()); 378} 379 380// Creates a new folder and selects a different folder for the folder to appear 381// in then the editor is initially created showing. 382TEST_F(BookmarkEditorViewTest, MoveFolder) { 383 BookmarkEditor::EditDetails details = BookmarkEditor::EditDetails::AddFolder( 384 model_->bookmark_bar_node(), -1); 385 details.urls.push_back(std::make_pair(GURL(base_path() + "x"), 386 ASCIIToUTF16("z"))); 387 CreateEditor(profile_.get(), model_->bookmark_bar_node(), 388 details, BookmarkEditorView::SHOW_TREE); 389 390 SetTitleText(L"new_F"); 391 392 // Create the folder in the 'other' folder. 393 ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1)); 394 395 // Make sure the folder we edited is still there. 396 ASSERT_EQ(3, model_->other_node()->child_count()); 397 const BookmarkNode* new_node = model_->other_node()->GetChild(2); 398 EXPECT_EQ(BookmarkNode::FOLDER, new_node->type()); 399 EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle()); 400 // The node should have one child. 401 ASSERT_EQ(1, new_node->child_count()); 402 const BookmarkNode* new_child = new_node->GetChild(0); 403 // Make sure the child url/title match. 404 EXPECT_EQ(BookmarkNode::URL, new_child->type()); 405 EXPECT_EQ(details.urls[0].second, new_child->GetTitle()); 406 EXPECT_EQ(details.urls[0].first, new_child->url()); 407} 408 409// Verifies the title of a new folder is updated correctly if ApplyEdits() is 410// is invoked while focus is still on the text field. 411TEST_F(BookmarkEditorViewTest, NewFolderTitleUpdatedOnCommit) { 412 const BookmarkNode* parent = 413 BookmarkModelFactory::GetForProfile(profile_.get())-> 414 bookmark_bar_node() ->GetChild(2); 415 416 CreateEditor(profile_.get(), parent, 417 BookmarkEditor::EditDetails::AddNodeInFolder( 418 parent, 1, GURL(), base::string16()), 419 BookmarkEditorView::SHOW_TREE); 420 ExpandAndSelect(); 421 422 SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec())); 423 SetTitleText(L"new_a"); 424 425 NewFolder(); 426 ASSERT_TRUE(tree_view()->editor() != NULL); 427 tree_view()->editor()->SetText(ASCIIToUTF16("modified")); 428 ApplyEdits(); 429 430 // Verify the new folder was added and title set appropriately. 431 ASSERT_EQ(1, parent->child_count()); 432 const BookmarkNode* new_folder = parent->GetChild(0); 433 ASSERT_TRUE(new_folder->is_folder()); 434 EXPECT_EQ("modified", UTF16ToASCII(new_folder->GetTitle())); 435} 436