root/chrome/browser/ui/views/bookmarks/bookmark_editor_view_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. model_
  2. SetUp
  3. TearDown
  4. base_path
  5. GetNode
  6. GetMutableNode
  7. editor_tree_model
  8. CreateEditor
  9. SetTitleText
  10. SetURLText
  11. ApplyEdits
  12. ApplyEdits
  13. AddNewFolder
  14. NewFolder
  15. URLTFHasParent
  16. ExpandAndSelect
  17. tree_view
  18. AddTestData
  19. TEST_F
  20. TEST_F
  21. TEST_F
  22. TEST_F
  23. TEST_F
  24. TEST_F
  25. TEST_F
  26. TEST_F
  27. TEST_F
  28. TEST_F
  29. TEST_F
  30. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/bookmarks/bookmark_editor_view.h"

#include <string>

#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/bookmark_test_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/tree/tree_view.h"

using base::ASCIIToUTF16;
using base::Time;
using base::TimeDelta;
using content::BrowserThread;

// Base class for bookmark editor tests. Creates a BookmarkModel and populates
// it with test data.
class BookmarkEditorViewTest : public testing::Test {
 public:
  BookmarkEditorViewTest()
      : ui_thread_(BrowserThread::UI, &message_loop_),
        file_thread_(BrowserThread::FILE, &message_loop_),
        model_(NULL) {
  }

  virtual void SetUp() {
    profile_.reset(new TestingProfile());
    profile_->CreateBookmarkModel(true);

    model_ = BookmarkModelFactory::GetForProfile(profile_.get());
    test::WaitForBookmarkModelToLoad(model_);

    AddTestData();
  }

  virtual void TearDown() {
  }

 protected:
  std::string base_path() const { return "file:///c:/tmp/"; }

  const BookmarkNode* GetNode(const std::string& name) {
    return model_->GetMostRecentlyAddedNodeForURL(GURL(base_path() + name));
  }

  BookmarkNode* GetMutableNode(const std::string& name) {
    return const_cast<BookmarkNode*>(GetNode(name));
  }

  BookmarkEditorView::EditorTreeModel* editor_tree_model() {
    return editor_->tree_model_.get();
  }

  void CreateEditor(Profile* profile,
                    const BookmarkNode* parent,
                    const BookmarkEditor::EditDetails& details,
                    BookmarkEditor::Configuration configuration) {
    editor_.reset(new BookmarkEditorView(profile, parent, details,
                                         configuration));
  }

  void SetTitleText(const base::string16& title) {
    editor_->title_tf_->SetText(title);
  }

  void SetURLText(const base::string16& text) {
    if (editor_->details_.type != BookmarkEditor::EditDetails::NEW_FOLDER)
      editor_->url_tf_->SetText(text);
  }

  void ApplyEdits() {
    editor_->ApplyEdits();
  }

  void ApplyEdits(BookmarkEditorView::EditorNode* node) {
    editor_->ApplyEdits(node);
  }

  BookmarkEditorView::EditorNode* AddNewFolder(
      BookmarkEditorView::EditorNode* parent) {
    return editor_->AddNewFolder(parent);
  }

  void NewFolder() {
    return editor_->NewFolder();
  }

  bool URLTFHasParent() {
    if (editor_->details_.type == BookmarkEditor::EditDetails::NEW_FOLDER)
      return false;
    return editor_->url_tf_->parent();
  }

  void ExpandAndSelect() {
    editor_->ExpandAndSelect();
  }

  views::TreeView* tree_view() { return editor_->tree_view_; }

  base::MessageLoopForUI message_loop_;
  content::TestBrowserThread ui_thread_;
  content::TestBrowserThread file_thread_;

  BookmarkModel* model_;
  scoped_ptr<TestingProfile> profile_;

 private:
  // Creates the following structure:
  // bookmark bar node
  //   a
  //   F1
  //    f1a
  //    F11
  //     f11a
  //   F2
  // other node
  //   oa
  //   OF1
  //     of1a
  void AddTestData() {
    const BookmarkNode* bb_node = model_->bookmark_bar_node();
    std::string test_base = base_path();
    model_->AddURL(bb_node, 0, ASCIIToUTF16("a"), GURL(test_base + "a"));
    const BookmarkNode* f1 = model_->AddFolder(bb_node, 1, ASCIIToUTF16("F1"));
    model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
    const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
    model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
    model_->AddFolder(bb_node, 2, ASCIIToUTF16("F2"));

    // Children of the other node.
    model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
                   GURL(test_base + "oa"));
    const BookmarkNode* of1 =
        model_->AddFolder(model_->other_node(), 1, ASCIIToUTF16("OF1"));
    model_->AddURL(of1, 0, ASCIIToUTF16("of1a"), GURL(test_base + "of1a"));
  }

  scoped_ptr<BookmarkEditorView> editor_;
};

// Makes sure the tree model matches that of the bookmark bar model.
TEST_F(BookmarkEditorViewTest, ModelsMatch) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::AddNodeInFolder(
                   NULL, -1, GURL(), base::string16()),
               BookmarkEditorView::SHOW_TREE);
  BookmarkEditorView::EditorNode* editor_root = editor_tree_model()->GetRoot();
  // The root should have two or three children: bookmark bar, other bookmarks
  // and conditionally mobile bookmarks.
  if (model_->mobile_node()->IsVisible()) {
    ASSERT_EQ(3, editor_root->child_count());
  } else {
    ASSERT_EQ(2, editor_root->child_count());
  }

  BookmarkEditorView::EditorNode* bb_node = editor_root->GetChild(0);
  // The root should have 2 nodes: folder F1 and F2.
  ASSERT_EQ(2, bb_node->child_count());
  ASSERT_EQ(ASCIIToUTF16("F1"), bb_node->GetChild(0)->GetTitle());
  ASSERT_EQ(ASCIIToUTF16("F2"), bb_node->GetChild(1)->GetTitle());

  // F1 should have one child, F11
  ASSERT_EQ(1, bb_node->GetChild(0)->child_count());
  ASSERT_EQ(ASCIIToUTF16("F11"), bb_node->GetChild(0)->GetChild(0)->GetTitle());

  BookmarkEditorView::EditorNode* other_node = editor_root->GetChild(1);
  // Other node should have one child (OF1).
  ASSERT_EQ(1, other_node->child_count());
  ASSERT_EQ(ASCIIToUTF16("OF1"), other_node->GetChild(0)->GetTitle());
}

// Changes the title and makes sure parent/visual order doesn't change.
TEST_F(BookmarkEditorViewTest, EditTitleKeepsPosition) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(GetNode("a")),
               BookmarkEditorView::SHOW_TREE);
  SetTitleText(L"new_a");

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));

  const BookmarkNode* bb_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node();
  ASSERT_EQ(ASCIIToUTF16("new_a"), bb_node->GetChild(0)->GetTitle());
  // The URL shouldn't have changed.
  ASSERT_TRUE(GURL(base_path() + "a") == bb_node->GetChild(0)->url());
}

// Changes the url and makes sure parent/visual order doesn't change.
TEST_F(BookmarkEditorViewTest, EditURLKeepsPosition) {
  Time node_time = Time::Now() + TimeDelta::FromDays(2);
  GetMutableNode("a")->set_date_added(node_time);
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(GetNode("a")),
               BookmarkEditorView::SHOW_TREE);

  SetURLText(base::UTF8ToWide(GURL(base_path() + "new_a").spec()));

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));

  const BookmarkNode* bb_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node();
  ASSERT_EQ(ASCIIToUTF16("a"), bb_node->GetChild(0)->GetTitle());
  // The URL should have changed.
  ASSERT_TRUE(GURL(base_path() + "new_a") == bb_node->GetChild(0)->url());
  ASSERT_TRUE(node_time == bb_node->GetChild(0)->date_added());
}

// Moves 'a' to be a child of the other node.
TEST_F(BookmarkEditorViewTest, ChangeParent) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(GetNode("a")),
               BookmarkEditorView::SHOW_TREE);

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));

  const BookmarkNode* other_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->other_node();
  ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
  ASSERT_TRUE(GURL(base_path() + "a") == other_node->GetChild(2)->url());
}

// Moves 'a' to be a child of the other node and changes its url to new_a.
TEST_F(BookmarkEditorViewTest, ChangeParentAndURL) {
  Time node_time = Time::Now() + TimeDelta::FromDays(2);
  GetMutableNode("a")->set_date_added(node_time);
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(GetNode("a")),
               BookmarkEditorView::SHOW_TREE);

  SetURLText(base::UTF8ToWide(GURL(base_path() + "new_a").spec()));

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));

  const BookmarkNode* other_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->other_node();
  ASSERT_EQ(ASCIIToUTF16("a"), other_node->GetChild(2)->GetTitle());
  ASSERT_TRUE(GURL(base_path() + "new_a") == other_node->GetChild(2)->url());
  ASSERT_TRUE(node_time == other_node->GetChild(2)->date_added());
}

// Creates a new folder and moves a node to it.
TEST_F(BookmarkEditorViewTest, MoveToNewParent) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(GetNode("a")),
               BookmarkEditorView::SHOW_TREE);

  // Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21".
  BookmarkEditorView::EditorNode* f2 =
      editor_tree_model()->GetRoot()->GetChild(0)->GetChild(1);
  BookmarkEditorView::EditorNode* f21 = AddNewFolder(f2);
  f21->SetTitle(ASCIIToUTF16("F21"));
  BookmarkEditorView::EditorNode* f211 = AddNewFolder(f21);
  f211->SetTitle(ASCIIToUTF16("F211"));

  // Parent the node to "F21".
  ApplyEdits(f2);

  const BookmarkNode* bb_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node();
  const BookmarkNode* mf2 = bb_node->GetChild(1);

  // F2 in the model should have two children now: F21 and the node edited.
  ASSERT_EQ(2, mf2->child_count());
  // F21 should be first.
  ASSERT_EQ(ASCIIToUTF16("F21"), mf2->GetChild(0)->GetTitle());
  // Then a.
  ASSERT_EQ(ASCIIToUTF16("a"), mf2->GetChild(1)->GetTitle());

  // F21 should have one child, F211.
  const BookmarkNode* mf21 = mf2->GetChild(0);
  ASSERT_EQ(1, mf21->child_count());
  ASSERT_EQ(ASCIIToUTF16("F211"), mf21->GetChild(0)->GetTitle());
}

// Brings up the editor, creating a new URL on the bookmark bar.
TEST_F(BookmarkEditorViewTest, NewURL) {
  const BookmarkNode* bb_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->bookmark_bar_node();

  CreateEditor(profile_.get(), bb_node,
               BookmarkEditor::EditDetails::AddNodeInFolder(
                   bb_node, 1, GURL(), base::string16()),
               BookmarkEditorView::SHOW_TREE);

  SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec()));
  SetTitleText(L"new_a");

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));

  ASSERT_EQ(4, bb_node->child_count());

  const BookmarkNode* new_node = bb_node->GetChild(1);

  EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
  EXPECT_TRUE(GURL(base_path() + "a") == new_node->url());
}

// Brings up the editor with no tree and modifies the url.
TEST_F(BookmarkEditorViewTest, ChangeURLNoTree) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(
                 model_->other_node()->GetChild(0)),
               BookmarkEditorView::NO_TREE);

  SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec()));
  SetTitleText(L"new_a");

  ApplyEdits(NULL);

  const BookmarkNode* other_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->other_node();
  ASSERT_EQ(2, other_node->child_count());

  const BookmarkNode* new_node = other_node->GetChild(0);

  EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
  EXPECT_TRUE(GURL(base_path() + "a") == new_node->url());
}

// Brings up the editor with no tree and modifies only the title.
TEST_F(BookmarkEditorViewTest, ChangeTitleNoTree) {
  CreateEditor(profile_.get(), NULL,
               BookmarkEditor::EditDetails::EditNode(
                 model_->other_node()->GetChild(0)),
               BookmarkEditorView::NO_TREE);

  SetTitleText(L"new_a");

  ApplyEdits(NULL);

  const BookmarkNode* other_node =
      BookmarkModelFactory::GetForProfile(profile_.get())->other_node();
  ASSERT_EQ(2, other_node->child_count());

  const BookmarkNode* new_node = other_node->GetChild(0);

  EXPECT_EQ(ASCIIToUTF16("new_a"), new_node->GetTitle());
}

// Creates a new folder.
TEST_F(BookmarkEditorViewTest, NewFolder) {
  const BookmarkNode* bb_node = model_->bookmark_bar_node();
  BookmarkEditor::EditDetails details =
      BookmarkEditor::EditDetails::AddFolder(bb_node, 1);
  details.urls.push_back(std::make_pair(GURL(base_path() + "x"),
                                        ASCIIToUTF16("z")));
  CreateEditor(profile_.get(), bb_node, details, BookmarkEditorView::SHOW_TREE);

  // The url field shouldn't be visible.
  EXPECT_FALSE(URLTFHasParent());
  SetTitleText(L"new_F");

  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(0));

  // Make sure the folder was created.
  ASSERT_EQ(4, bb_node->child_count());
  const BookmarkNode* new_node = bb_node->GetChild(1);
  EXPECT_EQ(BookmarkNode::FOLDER, new_node->type());
  EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle());
  // The node should have one child.
  ASSERT_EQ(1, new_node->child_count());
  const BookmarkNode* new_child = new_node->GetChild(0);
  // Make sure the child url/title match.
  EXPECT_EQ(BookmarkNode::URL, new_child->type());
  EXPECT_EQ(details.urls[0].second, new_child->GetTitle());
  EXPECT_EQ(details.urls[0].first, new_child->url());
}

// Creates a new folder and selects a different folder for the folder to appear
// in then the editor is initially created showing.
TEST_F(BookmarkEditorViewTest, MoveFolder) {
  BookmarkEditor::EditDetails details = BookmarkEditor::EditDetails::AddFolder(
      model_->bookmark_bar_node(), -1);
  details.urls.push_back(std::make_pair(GURL(base_path() + "x"),
                                        ASCIIToUTF16("z")));
  CreateEditor(profile_.get(), model_->bookmark_bar_node(),
               details, BookmarkEditorView::SHOW_TREE);

  SetTitleText(L"new_F");

  // Create the folder in the 'other' folder.
  ApplyEdits(editor_tree_model()->GetRoot()->GetChild(1));

  // Make sure the folder we edited is still there.
  ASSERT_EQ(3, model_->other_node()->child_count());
  const BookmarkNode* new_node = model_->other_node()->GetChild(2);
  EXPECT_EQ(BookmarkNode::FOLDER, new_node->type());
  EXPECT_EQ(ASCIIToUTF16("new_F"), new_node->GetTitle());
  // The node should have one child.
  ASSERT_EQ(1, new_node->child_count());
  const BookmarkNode* new_child = new_node->GetChild(0);
  // Make sure the child url/title match.
  EXPECT_EQ(BookmarkNode::URL, new_child->type());
  EXPECT_EQ(details.urls[0].second, new_child->GetTitle());
  EXPECT_EQ(details.urls[0].first, new_child->url());
}

// Verifies the title of a new folder is updated correctly if ApplyEdits() is
// is invoked while focus is still on the text field.
TEST_F(BookmarkEditorViewTest, NewFolderTitleUpdatedOnCommit) {
  const BookmarkNode* parent =
      BookmarkModelFactory::GetForProfile(profile_.get())->
      bookmark_bar_node() ->GetChild(2);

  CreateEditor(profile_.get(), parent,
               BookmarkEditor::EditDetails::AddNodeInFolder(
                   parent, 1, GURL(), base::string16()),
               BookmarkEditorView::SHOW_TREE);
  ExpandAndSelect();

  SetURLText(base::UTF8ToWide(GURL(base_path() + "a").spec()));
  SetTitleText(L"new_a");

  NewFolder();
  ASSERT_TRUE(tree_view()->editor() != NULL);
  tree_view()->editor()->SetText(ASCIIToUTF16("modified"));
  ApplyEdits();

  // Verify the new folder was added and title set appropriately.
  ASSERT_EQ(1, parent->child_count());
  const BookmarkNode* new_folder = parent->GetChild(0);
  ASSERT_TRUE(new_folder->is_folder());
  EXPECT_EQ("modified", base::UTF16ToASCII(new_folder->GetTitle()));
}

/* [<][>][^][v][top][bottom][index][help] */