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