Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/bookmarks/browser/bookmark_model.h" | 5 #include "components/bookmarks/browser/bookmark_model.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/base_paths.h" | 10 #include "base/base_paths.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 BookmarkNode* AsMutable(const BookmarkNode* node) { | 96 BookmarkNode* AsMutable(const BookmarkNode* node) { |
| 97 return const_cast<BookmarkNode*>(node); | 97 return const_cast<BookmarkNode*>(node); |
| 98 } | 98 } |
| 99 | 99 |
| 100 void SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) { | 100 void SwapDateAdded(BookmarkNode* n1, BookmarkNode* n2) { |
| 101 Time tmp = n1->date_added(); | 101 Time tmp = n1->date_added(); |
| 102 n1->set_date_added(n2->date_added()); | 102 n1->set_date_added(n2->date_added()); |
| 103 n2->set_date_added(tmp); | 103 n2->set_date_added(tmp); |
| 104 } | 104 } |
| 105 | 105 |
| 106 // See comment in PopulateNodeFromString. | |
| 107 typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode; | |
|
sky
2015/05/15 00:45:55
typedef->using
tfarina
2015/05/15 16:38:22
Done.
| |
| 108 | |
| 109 // Does the work of PopulateNodeFromString. index gives the index of the current | |
| 110 // element in description to process. | |
| 111 void PopulateNodeImpl(const std::vector<std::string>& description, | |
| 112 size_t* index, | |
| 113 TestNode* parent) { | |
| 114 while (*index < description.size()) { | |
| 115 const std::string& element = description[*index]; | |
| 116 (*index)++; | |
| 117 if (element == "[") { | |
| 118 // Create a new folder and recurse to add all the children. | |
| 119 // Folders are given a unique named by way of an ever increasing integer | |
| 120 // value. The folders need not have a name, but one is assigned to help | |
| 121 // in debugging. | |
| 122 static int next_folder_id = 1; | |
| 123 TestNode* new_node = new TestNode(base::IntToString16(next_folder_id++), | |
| 124 BookmarkNode::FOLDER); | |
| 125 parent->Add(new_node, parent->child_count()); | |
| 126 PopulateNodeImpl(description, index, new_node); | |
| 127 } else if (element == "]") { | |
| 128 // End the current folder. | |
| 129 return; | |
| 130 } else { | |
| 131 // Add a new URL. | |
| 132 | |
| 133 // All tokens must be space separated. If there is a [ or ] in the name it | |
| 134 // likely means a space was forgotten. | |
| 135 DCHECK(element.find('[') == std::string::npos); | |
| 136 DCHECK(element.find(']') == std::string::npos); | |
| 137 parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), | |
| 138 parent->child_count()); | |
| 139 } | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // Creates and adds nodes to parent based on description. description consists | |
| 144 // of the following tokens (all space separated): | |
| 145 // [ : creates a new USER_FOLDER node. All elements following the [ until the | |
| 146 // next balanced ] is encountered are added as children to the node. | |
| 147 // ] : closes the last folder created by [ so that any further nodes are added | |
| 148 // to the current folders parent. | |
| 149 // text: creates a new URL node. | |
| 150 // For example, "a [b] c" creates the following nodes: | |
| 151 // a 1 c | |
| 152 // | | |
| 153 // b | |
| 154 // In words: a node of type URL with the title a, followed by a folder node with | |
| 155 // the title 1 having the single child of type url with name b, followed by | |
| 156 // the url node with the title c. | |
| 157 // | |
| 158 // NOTE: each name must be unique, and folders are assigned a unique title by | |
| 159 // way of an increasing integer. | |
| 160 void PopulateNodeFromString(const std::string& description, TestNode* parent) { | |
| 161 std::vector<std::string> elements; | |
| 162 base::SplitStringAlongWhitespace(description, &elements); | |
| 163 size_t index = 0; | |
| 164 PopulateNodeImpl(elements, &index, parent); | |
| 165 } | |
| 166 | |
| 167 // Populates the BookmarkNode with the children of parent. | |
| 168 void PopulateBookmarkNode(TestNode* parent, | |
| 169 BookmarkModel* model, | |
| 170 const BookmarkNode* bb_node) { | |
| 171 for (int i = 0; i < parent->child_count(); ++i) { | |
| 172 TestNode* child = parent->GetChild(i); | |
| 173 if (child->value == BookmarkNode::FOLDER) { | |
| 174 const BookmarkNode* new_bb_node = | |
| 175 model->AddFolder(bb_node, i, child->GetTitle()); | |
| 176 PopulateBookmarkNode(child, model, new_bb_node); | |
| 177 } else { | |
| 178 model->AddURL(bb_node, i, child->GetTitle(), | |
| 179 GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); | |
| 180 } | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 // Verifies the contents of the bookmark bar node match the contents of the | |
| 185 // TestNode. | |
| 186 void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { | |
| 187 ASSERT_EQ(expected->child_count(), actual->child_count()); | |
| 188 for (int i = 0; i < expected->child_count(); ++i) { | |
| 189 TestNode* expected_child = expected->GetChild(i); | |
| 190 const BookmarkNode* actual_child = actual->GetChild(i); | |
| 191 ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); | |
| 192 if (expected_child->value == BookmarkNode::FOLDER) { | |
| 193 ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); | |
| 194 // Recurse throught children. | |
| 195 VerifyModelMatchesNode(expected_child, actual_child); | |
| 196 } else { | |
| 197 // No need to check the URL, just the title is enough. | |
| 198 ASSERT_TRUE(actual_child->is_url()); | |
| 199 } | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 void VerifyNoDuplicateIDs(BookmarkModel* model) { | |
| 204 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); | |
| 205 base::hash_set<int64> ids; | |
| 206 while (it.has_next()) | |
| 207 ASSERT_TRUE(ids.insert(it.Next()->id()).second); | |
| 208 } | |
| 209 | |
| 106 class BookmarkModelTest : public testing::Test, | 210 class BookmarkModelTest : public testing::Test, |
| 107 public BookmarkModelObserver { | 211 public BookmarkModelObserver { |
| 108 public: | 212 public: |
| 109 struct ObserverDetails { | 213 struct ObserverDetails { |
| 110 ObserverDetails() { | 214 ObserverDetails() { |
| 111 Set(NULL, NULL, -1, -1); | 215 Set(NULL, NULL, -1, -1); |
| 112 } | 216 } |
| 113 | 217 |
| 114 void Set(const BookmarkNode* node1, | 218 void Set(const BookmarkNode* node1, |
| 115 const BookmarkNode* node2, | 219 const BookmarkNode* node2, |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 819 EXPECT_EQ(1U, bookmarks.size()); | 923 EXPECT_EQ(1U, bookmarks.size()); |
| 820 } | 924 } |
| 821 | 925 |
| 822 TEST_F(BookmarkModelTest, HasBookmarks) { | 926 TEST_F(BookmarkModelTest, HasBookmarks) { |
| 823 const GURL url("http://foo.com/"); | 927 const GURL url("http://foo.com/"); |
| 824 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url); | 928 model_->AddURL(model_->bookmark_bar_node(), 0, ASCIIToUTF16("bar"), url); |
| 825 | 929 |
| 826 EXPECT_TRUE(model_->HasBookmarks()); | 930 EXPECT_TRUE(model_->HasBookmarks()); |
| 827 } | 931 } |
| 828 | 932 |
| 829 // See comment in PopulateNodeFromString. | |
| 830 typedef ui::TreeNodeWithValue<BookmarkNode::Type> TestNode; | |
| 831 | |
| 832 // Does the work of PopulateNodeFromString. index gives the index of the current | |
| 833 // element in description to process. | |
| 834 void PopulateNodeImpl(const std::vector<std::string>& description, | |
| 835 size_t* index, | |
| 836 TestNode* parent) { | |
| 837 while (*index < description.size()) { | |
| 838 const std::string& element = description[*index]; | |
| 839 (*index)++; | |
| 840 if (element == "[") { | |
| 841 // Create a new folder and recurse to add all the children. | |
| 842 // Folders are given a unique named by way of an ever increasing integer | |
| 843 // value. The folders need not have a name, but one is assigned to help | |
| 844 // in debugging. | |
| 845 static int next_folder_id = 1; | |
| 846 TestNode* new_node = | |
| 847 new TestNode(base::IntToString16(next_folder_id++), | |
| 848 BookmarkNode::FOLDER); | |
| 849 parent->Add(new_node, parent->child_count()); | |
| 850 PopulateNodeImpl(description, index, new_node); | |
| 851 } else if (element == "]") { | |
| 852 // End the current folder. | |
| 853 return; | |
| 854 } else { | |
| 855 // Add a new URL. | |
| 856 | |
| 857 // All tokens must be space separated. If there is a [ or ] in the name it | |
| 858 // likely means a space was forgotten. | |
| 859 DCHECK(element.find('[') == std::string::npos); | |
| 860 DCHECK(element.find(']') == std::string::npos); | |
| 861 parent->Add(new TestNode(base::UTF8ToUTF16(element), BookmarkNode::URL), | |
| 862 parent->child_count()); | |
| 863 } | |
| 864 } | |
| 865 } | |
| 866 | |
| 867 // Creates and adds nodes to parent based on description. description consists | |
| 868 // of the following tokens (all space separated): | |
| 869 // [ : creates a new USER_FOLDER node. All elements following the [ until the | |
| 870 // next balanced ] is encountered are added as children to the node. | |
| 871 // ] : closes the last folder created by [ so that any further nodes are added | |
| 872 // to the current folders parent. | |
| 873 // text: creates a new URL node. | |
| 874 // For example, "a [b] c" creates the following nodes: | |
| 875 // a 1 c | |
| 876 // | | |
| 877 // b | |
| 878 // In words: a node of type URL with the title a, followed by a folder node with | |
| 879 // the title 1 having the single child of type url with name b, followed by | |
| 880 // the url node with the title c. | |
| 881 // | |
| 882 // NOTE: each name must be unique, and folders are assigned a unique title by | |
| 883 // way of an increasing integer. | |
| 884 void PopulateNodeFromString(const std::string& description, TestNode* parent) { | |
| 885 std::vector<std::string> elements; | |
| 886 base::SplitStringAlongWhitespace(description, &elements); | |
| 887 size_t index = 0; | |
| 888 PopulateNodeImpl(elements, &index, parent); | |
| 889 } | |
| 890 | |
| 891 // Populates the BookmarkNode with the children of parent. | |
| 892 void PopulateBookmarkNode(TestNode* parent, | |
| 893 BookmarkModel* model, | |
| 894 const BookmarkNode* bb_node) { | |
| 895 for (int i = 0; i < parent->child_count(); ++i) { | |
| 896 TestNode* child = parent->GetChild(i); | |
| 897 if (child->value == BookmarkNode::FOLDER) { | |
| 898 const BookmarkNode* new_bb_node = | |
| 899 model->AddFolder(bb_node, i, child->GetTitle()); | |
| 900 PopulateBookmarkNode(child, model, new_bb_node); | |
| 901 } else { | |
| 902 model->AddURL(bb_node, i, child->GetTitle(), | |
| 903 GURL("http://" + base::UTF16ToASCII(child->GetTitle()))); | |
| 904 } | |
| 905 } | |
| 906 } | |
| 907 | |
| 908 // Test class that creates a BookmarkModel with a real history backend. | |
| 909 class BookmarkModelTestWithProfile : public testing::Test { | |
| 910 public: | |
| 911 BookmarkModelTestWithProfile() {} | |
| 912 | |
| 913 protected: | |
| 914 // Verifies the contents of the bookmark bar node match the contents of the | |
| 915 // TestNode. | |
| 916 void VerifyModelMatchesNode(TestNode* expected, const BookmarkNode* actual) { | |
| 917 ASSERT_EQ(expected->child_count(), actual->child_count()); | |
| 918 for (int i = 0; i < expected->child_count(); ++i) { | |
| 919 TestNode* expected_child = expected->GetChild(i); | |
| 920 const BookmarkNode* actual_child = actual->GetChild(i); | |
| 921 ASSERT_EQ(expected_child->GetTitle(), actual_child->GetTitle()); | |
| 922 if (expected_child->value == BookmarkNode::FOLDER) { | |
| 923 ASSERT_TRUE(actual_child->type() == BookmarkNode::FOLDER); | |
| 924 // Recurse throught children. | |
| 925 VerifyModelMatchesNode(expected_child, actual_child); | |
| 926 if (HasFatalFailure()) | |
| 927 return; | |
| 928 } else { | |
| 929 // No need to check the URL, just the title is enough. | |
| 930 ASSERT_TRUE(actual_child->is_url()); | |
| 931 } | |
| 932 } | |
| 933 } | |
| 934 | |
| 935 void VerifyNoDuplicateIDs(BookmarkModel* model) { | |
| 936 ui::TreeNodeIterator<const BookmarkNode> it(model->root_node()); | |
| 937 base::hash_set<int64> ids; | |
| 938 while (it.has_next()) | |
| 939 ASSERT_TRUE(ids.insert(it.Next()->id()).second); | |
| 940 } | |
| 941 | |
| 942 TestBookmarkClient client_; | |
| 943 scoped_ptr<BookmarkModel> model_; | |
| 944 }; | |
| 945 | |
| 946 // Creates a set of nodes in the bookmark bar model, then recreates the | |
| 947 // bookmark bar model which triggers loading from the db and checks the loaded | |
| 948 // structure to make sure it is what we first created. | |
| 949 TEST_F(BookmarkModelTestWithProfile, CreateAndRestore) { | |
| 950 struct TestData { | |
| 951 // Structure of the children of the bookmark bar model node. | |
| 952 const std::string bbn_contents; | |
| 953 // Structure of the children of the other node. | |
| 954 const std::string other_contents; | |
| 955 // Structure of the children of the synced node. | |
| 956 const std::string mobile_contents; | |
| 957 } data[] = { | |
| 958 // See PopulateNodeFromString for a description of these strings. | |
| 959 { "", "" }, | |
| 960 { "a", "b" }, | |
| 961 { "a [ b ]", "" }, | |
| 962 { "", "[ b ] a [ c [ d e [ f ] ] ]" }, | |
| 963 { "a [ b ]", "" }, | |
| 964 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, | |
| 965 }; | |
| 966 for (size_t i = 0; i < arraysize(data); ++i) { | |
| 967 model_ = client_.CreateModel(); | |
| 968 | |
| 969 TestNode bbn; | |
| 970 PopulateNodeFromString(data[i].bbn_contents, &bbn); | |
| 971 PopulateBookmarkNode(&bbn, model_.get(), model_->bookmark_bar_node()); | |
| 972 | |
| 973 TestNode other; | |
| 974 PopulateNodeFromString(data[i].other_contents, &other); | |
| 975 PopulateBookmarkNode(&other, model_.get(), model_->other_node()); | |
| 976 | |
| 977 TestNode mobile; | |
| 978 PopulateNodeFromString(data[i].mobile_contents, &mobile); | |
| 979 PopulateBookmarkNode(&mobile, model_.get(), model_->mobile_node()); | |
| 980 | |
| 981 VerifyModelMatchesNode(&bbn, model_->bookmark_bar_node()); | |
| 982 VerifyModelMatchesNode(&other, model_->other_node()); | |
| 983 VerifyModelMatchesNode(&mobile, model_->mobile_node()); | |
| 984 VerifyNoDuplicateIDs(model_.get()); | |
| 985 } | |
| 986 } | |
| 987 | |
| 988 // http://crbug.com/450464 | 933 // http://crbug.com/450464 |
| 989 TEST_F(BookmarkModelTest, DISABLED_Sort) { | 934 TEST_F(BookmarkModelTest, DISABLED_Sort) { |
| 990 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'. | 935 // Populate the bookmark bar node with nodes for 'B', 'a', 'd' and 'C'. |
| 991 // 'C' and 'a' are folders. | 936 // 'C' and 'a' are folders. |
| 992 TestNode bbn; | 937 TestNode bbn; |
| 993 PopulateNodeFromString("B [ a ] d [ a ]", &bbn); | 938 PopulateNodeFromString("B [ a ] d [ a ]", &bbn); |
| 994 const BookmarkNode* parent = model_->bookmark_bar_node(); | 939 const BookmarkNode* parent = model_->bookmark_bar_node(); |
| 995 PopulateBookmarkNode(&bbn, model_.get(), parent); | 940 PopulateBookmarkNode(&bbn, model_.get(), parent); |
| 996 | 941 |
| 997 BookmarkNode* child1 = AsMutable(parent->GetChild(1)); | 942 BookmarkNode* child1 = AsMutable(parent->GetChild(1)); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1186 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1")); | 1131 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey1")); |
| 1187 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf")); | 1132 EXPECT_TRUE(node.DeleteMetaInfo("key2.subkey2.leaf")); |
| 1188 EXPECT_FALSE(node.DeleteMetaInfo("key3")); | 1133 EXPECT_FALSE(node.DeleteMetaInfo("key3")); |
| 1189 EXPECT_FALSE(node.GetMetaInfo("key1", &out_value)); | 1134 EXPECT_FALSE(node.GetMetaInfo("key1", &out_value)); |
| 1190 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); | 1135 EXPECT_FALSE(node.GetMetaInfo("key2.subkey1", &out_value)); |
| 1191 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value)); | 1136 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2", &out_value)); |
| 1192 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); | 1137 EXPECT_FALSE(node.GetMetaInfo("key2.subkey2.leaf", &out_value)); |
| 1193 EXPECT_FALSE(node.GetMetaInfoMap()); | 1138 EXPECT_FALSE(node.GetMetaInfoMap()); |
| 1194 } | 1139 } |
| 1195 | 1140 |
| 1141 // Creates a set of nodes in the bookmark model, and checks that the loaded | |
| 1142 // structure is what we first created. | |
| 1143 TEST(BookmarkModelTest2, CreateAndRestore) { | |
| 1144 struct TestData { | |
| 1145 // Structure of the children of the bookmark model node. | |
| 1146 const std::string bbn_contents; | |
| 1147 // Structure of the children of the other node. | |
| 1148 const std::string other_contents; | |
| 1149 // Structure of the children of the synced node. | |
| 1150 const std::string mobile_contents; | |
| 1151 } data[] = { | |
| 1152 // See PopulateNodeFromString for a description of these strings. | |
| 1153 { "", "" }, | |
| 1154 { "a", "b" }, | |
| 1155 { "a [ b ]", "" }, | |
| 1156 { "", "[ b ] a [ c [ d e [ f ] ] ]" }, | |
| 1157 { "a [ b ]", "" }, | |
| 1158 { "a b c [ d e [ f ] ]", "g h i [ j k [ l ] ]"}, | |
| 1159 }; | |
| 1160 TestBookmarkClient client; | |
| 1161 scoped_ptr<BookmarkModel> model; | |
| 1162 for (size_t i = 0; i < arraysize(data); ++i) { | |
| 1163 model = client.CreateModel(); | |
| 1164 | |
| 1165 TestNode bbn; | |
| 1166 PopulateNodeFromString(data[i].bbn_contents, &bbn); | |
| 1167 PopulateBookmarkNode(&bbn, model.get(), model->bookmark_bar_node()); | |
| 1168 | |
| 1169 TestNode other; | |
| 1170 PopulateNodeFromString(data[i].other_contents, &other); | |
| 1171 PopulateBookmarkNode(&other, model.get(), model->other_node()); | |
| 1172 | |
| 1173 TestNode mobile; | |
| 1174 PopulateNodeFromString(data[i].mobile_contents, &mobile); | |
| 1175 PopulateBookmarkNode(&mobile, model.get(), model->mobile_node()); | |
| 1176 | |
| 1177 VerifyModelMatchesNode(&bbn, model->bookmark_bar_node()); | |
| 1178 VerifyModelMatchesNode(&other, model->other_node()); | |
| 1179 VerifyModelMatchesNode(&mobile, model->mobile_node()); | |
| 1180 VerifyNoDuplicateIDs(model.get()); | |
| 1181 } | |
| 1182 } | |
| 1183 | |
| 1196 } // namespace | 1184 } // namespace |
| 1197 } // namespace bookmarks | 1185 } // namespace bookmarks |
| OLD | NEW |