|  | // 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/extensions/api/bookmarks/bookmark_api_helpers.h" | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/strings/string_number_conversions.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "base/values.h" | 
|  | #include "chrome/browser/bookmarks/bookmark_model_factory.h" | 
|  | #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h" | 
|  | #include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h" | 
|  | #include "chrome/common/extensions/api/bookmarks.h" | 
|  | #include "chrome/test/base/testing_profile.h" | 
|  | #include "components/bookmarks/browser/bookmark_model.h" | 
|  | #include "components/bookmarks/managed/managed_bookmark_service.h" | 
|  | #include "components/bookmarks/test/bookmark_test_helpers.h" | 
|  | #include "content/public/test/test_browser_thread_bundle.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | using bookmarks::BookmarkModel; | 
|  | using bookmarks::BookmarkNode; | 
|  |  | 
|  | namespace extensions { | 
|  |  | 
|  | namespace keys = bookmark_api_constants; | 
|  | using api::bookmarks::BookmarkTreeNode; | 
|  |  | 
|  | namespace bookmark_api_helpers { | 
|  |  | 
|  | class ExtensionBookmarksTest : public testing::Test { | 
|  | public: | 
|  | ExtensionBookmarksTest() | 
|  | : managed_(NULL), | 
|  | model_(NULL), | 
|  | node_(NULL), | 
|  | node2_(NULL), | 
|  | folder_(NULL) {} | 
|  |  | 
|  | void SetUp() override { | 
|  | profile_.CreateBookmarkModel(false); | 
|  | model_ = BookmarkModelFactory::GetForBrowserContext(&profile_); | 
|  | managed_ = ManagedBookmarkServiceFactory::GetForProfile(&profile_); | 
|  | bookmarks::test::WaitForBookmarkModelToLoad(model_); | 
|  |  | 
|  | node_ = model_->AddURL(model_->other_node(), 0, base::ASCIIToUTF16("Digg"), | 
|  | GURL("http://www.reddit.com")); | 
|  | model_->SetNodeMetaInfo(node_, "some_key1", "some_value1"); | 
|  | model_->SetNodeMetaInfo(node_, "some_key2", "some_value2"); | 
|  | model_->AddURL(model_->other_node(), 0, base::ASCIIToUTF16("News"), | 
|  | GURL("http://www.foxnews.com")); | 
|  | folder_ = model_->AddFolder( | 
|  | model_->other_node(), 0, base::ASCIIToUTF16("outer folder")); | 
|  | model_->SetNodeMetaInfo(folder_, "some_key1", "some_value1"); | 
|  | model_->AddFolder(folder_, 0, base::ASCIIToUTF16("inner folder 1")); | 
|  | model_->AddFolder(folder_, 0, base::ASCIIToUTF16("inner folder 2")); | 
|  | node2_ = model_->AddURL( | 
|  | folder_, 0, base::ASCIIToUTF16("Digg"), GURL("http://reddit.com")); | 
|  | model_->SetNodeMetaInfo(node2_, "some_key2", "some_value2"); | 
|  | model_->AddURL( | 
|  | folder_, 0, base::ASCIIToUTF16("CNet"), GURL("http://cnet.com")); | 
|  | } | 
|  |  | 
|  | content::TestBrowserThreadBundle thread_bundle_; | 
|  | TestingProfile profile_; | 
|  | bookmarks::ManagedBookmarkService* managed_; | 
|  | BookmarkModel* model_; | 
|  | const BookmarkNode* node_; | 
|  | const BookmarkNode* node2_; | 
|  | const BookmarkNode* folder_; | 
|  | }; | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetFullTreeFromRoot) { | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, model_->other_node(), | 
|  | true,    // Recurse. | 
|  | false);  // Not only folders. | 
|  | ASSERT_EQ(3U, tree.children->size()); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetFoldersOnlyFromRoot) { | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, model_->other_node(), | 
|  | true,   // Recurse. | 
|  | true);  // Only folders. | 
|  | ASSERT_EQ(1U, tree.children->size()); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetSubtree) { | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, folder_, | 
|  | true,    // Recurse. | 
|  | false);  // Not only folders. | 
|  | ASSERT_EQ(4U, tree.children->size()); | 
|  | const BookmarkTreeNode& digg = tree.children->at(1); | 
|  | ASSERT_EQ("Digg", digg.title); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetSubtreeFoldersOnly) { | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, folder_, | 
|  | true,   // Recurse. | 
|  | true);  // Only folders. | 
|  | ASSERT_EQ(2U, tree.children->size()); | 
|  | const BookmarkTreeNode& inner_folder = tree.children->at(1); | 
|  | ASSERT_EQ("inner folder 1", inner_folder.title); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetModifiableNode) { | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, node_, | 
|  | false,   // Recurse. | 
|  | false);  // Only folders. | 
|  | EXPECT_EQ("Digg", tree.title); | 
|  | ASSERT_TRUE(tree.url); | 
|  | EXPECT_EQ("http://www.reddit.com/", *tree.url); | 
|  | EXPECT_EQ(api::bookmarks::BOOKMARK_TREE_NODE_UNMODIFIABLE_NONE, | 
|  | tree.unmodifiable); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetManagedNode) { | 
|  | const BookmarkNode* managed_bookmark = | 
|  | model_->AddURL(managed_->managed_node(), | 
|  | 0, | 
|  | base::ASCIIToUTF16("Chromium"), | 
|  | GURL("http://www.chromium.org/")); | 
|  | BookmarkTreeNode tree = GetBookmarkTreeNode(managed_, managed_bookmark, | 
|  | false,   // Recurse. | 
|  | false);  // Only folders. | 
|  | EXPECT_EQ("Chromium", tree.title); | 
|  | EXPECT_EQ("http://www.chromium.org/", *tree.url); | 
|  | EXPECT_EQ(api::bookmarks::BOOKMARK_TREE_NODE_UNMODIFIABLE_MANAGED, | 
|  | tree.unmodifiable); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, RemoveNodeInvalidId) { | 
|  | int64_t invalid_id = model_->next_node_id(); | 
|  | std::string error; | 
|  | EXPECT_FALSE(RemoveNode(model_, managed_, invalid_id, true, &error)); | 
|  | EXPECT_EQ(keys::kNoNodeError, error); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, RemoveNodePermanent) { | 
|  | std::string error; | 
|  | EXPECT_FALSE( | 
|  | RemoveNode(model_, managed_, model_->other_node()->id(), true, &error)); | 
|  | EXPECT_EQ(keys::kModifySpecialError, error); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, RemoveNodeManaged) { | 
|  | const BookmarkNode* managed_bookmark = | 
|  | model_->AddURL(managed_->managed_node(), | 
|  | 0, | 
|  | base::ASCIIToUTF16("Chromium"), | 
|  | GURL("http://www.chromium.org")); | 
|  | std::string error; | 
|  | EXPECT_FALSE( | 
|  | RemoveNode(model_, managed_, managed_bookmark->id(), true, &error)); | 
|  | EXPECT_EQ(keys::kModifyManagedError, error); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, RemoveNodeNotRecursive) { | 
|  | std::string error; | 
|  | EXPECT_FALSE(RemoveNode(model_, managed_, folder_->id(), false, &error)); | 
|  | EXPECT_EQ(keys::kFolderNotEmptyError, error); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, RemoveNodeRecursive) { | 
|  | EXPECT_EQ(3, model_->other_node()->child_count()); | 
|  | std::string error; | 
|  | EXPECT_TRUE(RemoveNode(model_, managed_, folder_->id(), true, &error)); | 
|  | EXPECT_EQ(2, model_->other_node()->child_count()); | 
|  | } | 
|  |  | 
|  | TEST_F(ExtensionBookmarksTest, GetMetaInfo) { | 
|  | base::DictionaryValue id_to_meta_info_map; | 
|  | GetMetaInfo(*model_->other_node(), &id_to_meta_info_map); | 
|  | EXPECT_EQ(8u, id_to_meta_info_map.size()); | 
|  |  | 
|  | // Verify top level node. | 
|  | const base::Value* value = NULL; | 
|  | EXPECT_TRUE(id_to_meta_info_map.Get( | 
|  | base::Int64ToString(model_->other_node()->id()), &value)); | 
|  | ASSERT_TRUE(NULL != value); | 
|  | const base::DictionaryValue* dictionary_value = NULL; | 
|  | EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)); | 
|  | ASSERT_TRUE(NULL != dictionary_value); | 
|  | EXPECT_EQ(0u, dictionary_value->size()); | 
|  |  | 
|  | // Verify bookmark with two meta info key/value pairs. | 
|  | value = NULL; | 
|  | EXPECT_TRUE(id_to_meta_info_map.Get( | 
|  | base::Int64ToString(node_->id()), &value)); | 
|  | ASSERT_TRUE(NULL != value); | 
|  | dictionary_value = NULL; | 
|  | EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)); | 
|  | ASSERT_TRUE(NULL != dictionary_value); | 
|  | EXPECT_EQ(2u, dictionary_value->size()); | 
|  | std::string string_value; | 
|  | EXPECT_TRUE(dictionary_value->GetString("some_key1", &string_value)); | 
|  | EXPECT_EQ("some_value1", string_value); | 
|  | EXPECT_TRUE(dictionary_value->GetString("some_key2", &string_value)); | 
|  | EXPECT_EQ("some_value2", string_value); | 
|  |  | 
|  | // Verify folder with one meta info key/value pair. | 
|  | value = NULL; | 
|  | EXPECT_TRUE(id_to_meta_info_map.Get( | 
|  | base::Int64ToString(folder_->id()), &value)); | 
|  | ASSERT_TRUE(NULL != value); | 
|  | dictionary_value = NULL; | 
|  | EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)); | 
|  | ASSERT_TRUE(NULL != dictionary_value); | 
|  | EXPECT_EQ(1u, dictionary_value->size()); | 
|  | EXPECT_TRUE(dictionary_value->GetString("some_key1", &string_value)); | 
|  | EXPECT_EQ("some_value1", string_value); | 
|  |  | 
|  | // Verify bookmark in a subfolder with one meta info key/value pairs. | 
|  | value = NULL; | 
|  | EXPECT_TRUE(id_to_meta_info_map.Get( | 
|  | base::Int64ToString(node2_->id()), &value)); | 
|  | ASSERT_TRUE(NULL != value); | 
|  | dictionary_value = NULL; | 
|  | EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)); | 
|  | ASSERT_TRUE(NULL != dictionary_value); | 
|  | EXPECT_EQ(1u, dictionary_value->size()); | 
|  | string_value.clear(); | 
|  | EXPECT_FALSE(dictionary_value->GetString("some_key1", &string_value)); | 
|  | EXPECT_EQ("", string_value); | 
|  | EXPECT_TRUE(dictionary_value->GetString("some_key2", &string_value)); | 
|  | EXPECT_EQ("some_value2", string_value); | 
|  |  | 
|  | } | 
|  |  | 
|  | }  // namespace bookmark_api_helpers | 
|  | }  // namespace extensions |