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