OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 <iostream> |
| 6 #include <map> |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 10 #include "base/json/json_reader.h" |
| 11 #include "base/json/json_writer.h" |
| 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/values.h" |
| 14 #include "chrome/browser/supervised_user/supervised_user_bookmarks_handler.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 using Folder = SupervisedUserBookmarksHandler::Folder; |
| 18 using Link = SupervisedUserBookmarksHandler::Link; |
| 19 |
| 20 namespace { |
| 21 |
| 22 typedef std::pair<std::string, std::string> Setting; |
| 23 |
| 24 // Settings representing the following tree: |
| 25 // |--Folder1 |
| 26 // |--SubFolder |
| 27 // |--Empty SubSubFolder |
| 28 // |--Google(google.com) |
| 29 // |--(www.theoatmeal.com) |
| 30 // |--Test(www.test.de) |
| 31 // |--Empty Folder |
| 32 // |--XKCD(m.xkcd.com) |
| 33 |
| 34 // Folder setting format: "<ID>", "<ParentID>:<Name>" |
| 35 const Setting FOLDER_SETTINGS[] = { |
| 36 Setting("5", "0:Folder1"), |
| 37 Setting("9", "0:Empty Folder"), |
| 38 Setting("3", "5:SubFolder"), |
| 39 Setting("4", "3:Empty SubSubFolder"), |
| 40 }; |
| 41 |
| 42 const Setting FOLDER_SETTINGS_INVALID_PARENT[] = { |
| 43 Setting("5", "0:Folder1"), |
| 44 Setting("9", "7:Empty Folder"), // Invalid parent id. |
| 45 Setting("3", "5:SubFolder"), |
| 46 Setting("4", "3:Empty SubSubFolder"), |
| 47 }; |
| 48 |
| 49 const Setting FOLDER_SETTINGS_CIRCLE[] = { |
| 50 Setting("5", "3:Folder1"), |
| 51 Setting("9", "5:Empty Folder"), |
| 52 Setting("3", "9:SubFolder"), |
| 53 }; |
| 54 |
| 55 // Link setting format: "<ID>:<URL>", "<ParentID>:<Name>" |
| 56 const Setting LINK_SETTINGS[] = { |
| 57 Setting("4:www.theoatmeal.com", "3:"), |
| 58 Setting("1:m.xkcd.com", "0:XKCD"), |
| 59 Setting("2:www.test.de", "5:Test"), |
| 60 Setting("3:google.com", "3:Google"), |
| 61 }; |
| 62 |
| 63 const Setting LINK_SETTINGS_INVALID_PARENT[] = { |
| 64 Setting("4:www.theoatmeal.com", "3:"), |
| 65 Setting("1:m.xkcd.com", "7:XKCD"), // Invalid parent id. |
| 66 Setting("2:www.test.de", "8:Test"), // Invalid parent id. |
| 67 }; |
| 68 |
| 69 // Parsed data is sorted by ID (even though the parsed links don't actually |
| 70 // contain their IDs!) |
| 71 |
| 72 const Folder PARSED_FOLDERS[] = { |
| 73 Folder(3, "SubFolder", 5), // Note: Forward reference. |
| 74 Folder(4, "Empty SubSubFolder", 3), |
| 75 Folder(5, "Folder1", 0), |
| 76 Folder(9, "Empty Folder", 0), |
| 77 }; |
| 78 |
| 79 const Link PARSED_LINKS[] = { |
| 80 Link("m.xkcd.com", "XKCD", 0), |
| 81 Link("www.test.de", "Test", 5), |
| 82 Link("google.com", "Google", 3), |
| 83 Link("www.theoatmeal.com", std::string(), 3), |
| 84 }; |
| 85 |
| 86 const char BOOKMARKS_TREE_JSON[] = |
| 87 "[" |
| 88 " {" |
| 89 " \"id\":5," |
| 90 " \"name\":\"Folder1\"," |
| 91 " \"children\":[" |
| 92 " {" |
| 93 " \"id\":3," |
| 94 " \"name\":\"SubFolder\"," |
| 95 " \"children\":[" |
| 96 " {" |
| 97 " \"id\":4," |
| 98 " \"name\":\"Empty SubSubFolder\"," |
| 99 " \"children\":[]" |
| 100 " }," |
| 101 " {" |
| 102 " \"name\":\"Google\"," |
| 103 " \"url\":\"http://google.com/\"" |
| 104 " }," |
| 105 " {" |
| 106 " \"name\":\"\"," |
| 107 " \"url\":\"http://www.theoatmeal.com/\"" |
| 108 " }" |
| 109 " ]" |
| 110 " }," |
| 111 " {" |
| 112 " \"name\":\"Test\"," |
| 113 " \"url\":\"http://www.test.de/\"" |
| 114 " }" |
| 115 " ]" |
| 116 " }," |
| 117 " {" |
| 118 " \"id\":9," |
| 119 " \"name\":\"Empty Folder\"," |
| 120 " \"children\":[]" |
| 121 " }," |
| 122 " {" |
| 123 " \"name\":\"XKCD\"," |
| 124 " \"url\":\"http://m.xkcd.com/\"" |
| 125 " }" |
| 126 "]"; |
| 127 |
| 128 const char BOOKMARKS_TREE_INVALID_PARENTS_JSON[] = |
| 129 "[" |
| 130 " {" |
| 131 " \"id\":5," |
| 132 " \"name\":\"Folder1\"," |
| 133 " \"children\":[" |
| 134 " {" |
| 135 " \"id\":3," |
| 136 " \"name\":\"SubFolder\"," |
| 137 " \"children\":[" |
| 138 " {" |
| 139 " \"id\":4," |
| 140 " \"name\":\"Empty SubSubFolder\"," |
| 141 " \"children\":[]" |
| 142 " }," |
| 143 " {" |
| 144 " \"name\":\"\"," |
| 145 " \"url\":\"http://www.theoatmeal.com/\"" |
| 146 " }" |
| 147 " ]" |
| 148 " }" |
| 149 " ]" |
| 150 " }" |
| 151 "]"; |
| 152 |
| 153 // Builds the base::Values tree from a json string above. |
| 154 scoped_ptr<base::ListValue> CreateTree(const char* json) { |
| 155 base::Value* value = base::JSONReader::Read(json); |
| 156 EXPECT_NE(value, nullptr); |
| 157 base::ListValue* list; |
| 158 EXPECT_TRUE(value->GetAsList(&list)); |
| 159 return make_scoped_ptr(list); |
| 160 } |
| 161 |
| 162 scoped_ptr<base::ListValue> CreateBookmarksTree() { |
| 163 return CreateTree(BOOKMARKS_TREE_JSON); |
| 164 } |
| 165 |
| 166 scoped_ptr<base::ListValue> CreateBookmarksTreeWithInvalidParents() { |
| 167 return CreateTree(BOOKMARKS_TREE_INVALID_PARENTS_JSON); |
| 168 } |
| 169 |
| 170 } // namespace |
| 171 |
| 172 static bool operator==(const Folder& f1, const Folder& f2) { |
| 173 return f1.id == f2.id && f1.name == f2.name && f1.parent_id == f2.parent_id; |
| 174 } |
| 175 |
| 176 static bool operator==(const Link& l1, const Link& l2) { |
| 177 return l1.url == l2.url && l1.name == l2.name && l1.parent_id == l2.parent_id; |
| 178 } |
| 179 |
| 180 std::ostream& operator<<(std::ostream& str, const Folder& folder) { |
| 181 str << folder.id << " " << folder.name << " " << folder.parent_id; |
| 182 return str; |
| 183 } |
| 184 |
| 185 std::ostream& operator<<(std::ostream& str, const Link& link) { |
| 186 str << link.url << " " << link.name << " " << link.parent_id; |
| 187 return str; |
| 188 } |
| 189 |
| 190 class SupervisedUserBookmarksHandlerTest : public ::testing::Test { |
| 191 protected: |
| 192 static base::DictionaryValue* CreateSettings(base::DictionaryValue* links, |
| 193 base::DictionaryValue* folders) { |
| 194 base::DictionaryValue* settings = new base::DictionaryValue; |
| 195 settings->SetStringWithoutPathExpansion("some_setting", "bleh"); |
| 196 settings->SetWithoutPathExpansion("SupervisedBookmarkLink", links); |
| 197 settings->SetStringWithoutPathExpansion("some_other_setting", "foo"); |
| 198 settings->SetWithoutPathExpansion("SupervisedBookmarkFolder", folders); |
| 199 settings->SetStringWithoutPathExpansion("another_one", "blurb"); |
| 200 return settings; |
| 201 } |
| 202 |
| 203 static base::DictionaryValue* CreateDictionary(const Setting* begin, |
| 204 const Setting* end) { |
| 205 base::DictionaryValue* dict = new base::DictionaryValue; |
| 206 for (const Setting* setting = begin; setting != end; ++setting) |
| 207 dict->SetStringWithoutPathExpansion(setting->first, setting->second); |
| 208 return dict; |
| 209 } |
| 210 |
| 211 static base::DictionaryValue* CreateLinkDictionary() { |
| 212 return CreateDictionary(LINK_SETTINGS, |
| 213 LINK_SETTINGS + arraysize(LINK_SETTINGS)); |
| 214 } |
| 215 |
| 216 static base::DictionaryValue* CreateLinkDictionaryWithInvalidParents() { |
| 217 return CreateDictionary( |
| 218 LINK_SETTINGS_INVALID_PARENT, |
| 219 LINK_SETTINGS_INVALID_PARENT + arraysize(LINK_SETTINGS_INVALID_PARENT)); |
| 220 } |
| 221 |
| 222 static base::DictionaryValue* CreateFolderDictionary() { |
| 223 return CreateDictionary(FOLDER_SETTINGS, |
| 224 FOLDER_SETTINGS + arraysize(FOLDER_SETTINGS)); |
| 225 } |
| 226 |
| 227 static base::DictionaryValue* CreateFolderDictionaryWithInvalidParents() { |
| 228 return CreateDictionary( |
| 229 FOLDER_SETTINGS_INVALID_PARENT, |
| 230 FOLDER_SETTINGS_INVALID_PARENT + |
| 231 arraysize(FOLDER_SETTINGS_INVALID_PARENT)); |
| 232 } |
| 233 |
| 234 static base::DictionaryValue* CreateFolderDictionaryWithCircle() { |
| 235 return CreateDictionary( |
| 236 FOLDER_SETTINGS_CIRCLE, |
| 237 FOLDER_SETTINGS_CIRCLE + arraysize(FOLDER_SETTINGS_CIRCLE)); |
| 238 } |
| 239 |
| 240 void ParseFolders(const base::DictionaryValue& folders) { |
| 241 deserializer_.ParseFolders(folders); |
| 242 } |
| 243 |
| 244 void ParseLinks(const base::DictionaryValue& links) { |
| 245 deserializer_.ParseLinks(links); |
| 246 } |
| 247 |
| 248 const std::vector<Folder>& GetFolders() const { |
| 249 return deserializer_.folders_for_testing(); |
| 250 } |
| 251 |
| 252 const std::vector<Link>& GetLinks() const { |
| 253 return deserializer_.links_for_testing(); |
| 254 } |
| 255 |
| 256 private: |
| 257 SupervisedUserBookmarksHandler deserializer_; |
| 258 }; |
| 259 |
| 260 TEST_F(SupervisedUserBookmarksHandlerTest, ParseSettings) { |
| 261 scoped_ptr<base::DictionaryValue> link_dictionary(CreateLinkDictionary()); |
| 262 scoped_ptr<base::DictionaryValue> folder_dictionary(CreateFolderDictionary()); |
| 263 |
| 264 ParseLinks(*link_dictionary.get()); |
| 265 ParseFolders(*folder_dictionary.get()); |
| 266 |
| 267 const std::vector<Link>& links = GetLinks(); |
| 268 EXPECT_EQ(arraysize(PARSED_LINKS), links.size()); |
| 269 for (size_t i = 0; i < links.size(); ++i) |
| 270 EXPECT_EQ(PARSED_LINKS[i], links[i]); |
| 271 |
| 272 const std::vector<Folder>& folders = GetFolders(); |
| 273 EXPECT_EQ(arraysize(PARSED_FOLDERS), folders.size()); |
| 274 for (size_t i = 0; i < folders.size(); ++i) |
| 275 EXPECT_EQ(PARSED_FOLDERS[i], folders[i]); |
| 276 } |
| 277 |
| 278 TEST_F(SupervisedUserBookmarksHandlerTest, BuildBookmarksTree) { |
| 279 // Make some fake settings. |
| 280 scoped_ptr<base::DictionaryValue> settings( |
| 281 CreateSettings(CreateLinkDictionary(), CreateFolderDictionary())); |
| 282 // Parse the settings into a bookmarks tree. |
| 283 scoped_ptr<base::ListValue> bookmarks( |
| 284 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings.get())); |
| 285 |
| 286 // Check that the parsed tree matches the expected tree constructed directly |
| 287 // from the hardcoded json above. |
| 288 scoped_ptr<base::ListValue> expected_bookmarks(CreateBookmarksTree()); |
| 289 EXPECT_TRUE(bookmarks->Equals(expected_bookmarks.get())); |
| 290 } |
| 291 |
| 292 TEST_F(SupervisedUserBookmarksHandlerTest, |
| 293 BuildBookmarksTreeWithInvalidParents) { |
| 294 // Make some fake settings, including some entries with invalid parent |
| 295 // references. |
| 296 scoped_ptr<base::DictionaryValue> settings( |
| 297 CreateSettings(CreateLinkDictionaryWithInvalidParents(), |
| 298 CreateFolderDictionaryWithInvalidParents())); |
| 299 // Parse the settings into a bookmarks tree. |
| 300 scoped_ptr<base::ListValue> bookmarks( |
| 301 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings.get())); |
| 302 |
| 303 // Check that the parsed tree matches the expected tree constructed directly |
| 304 // from the hardcoded json above (which does not contain the entries with |
| 305 // invalid parents!). |
| 306 scoped_ptr<base::ListValue> expected_bookmarks( |
| 307 CreateBookmarksTreeWithInvalidParents()); |
| 308 EXPECT_TRUE(bookmarks->Equals(expected_bookmarks.get())); |
| 309 } |
| 310 |
| 311 TEST_F(SupervisedUserBookmarksHandlerTest, Circle) { |
| 312 // Make some fake settings which include a circular reference in the folders. |
| 313 scoped_ptr<base::DictionaryValue> settings( |
| 314 CreateSettings(CreateLinkDictionary(), |
| 315 CreateFolderDictionaryWithCircle())); |
| 316 scoped_ptr<base::ListValue> bookmarks( |
| 317 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings.get())); |
| 318 // Don't care what exactly the result looks like, just that we don't run into |
| 319 // an endless loop. |
| 320 } |
OLD | NEW |