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.
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/macros.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/values.h"
15 #include "chrome/browser/supervised_user/supervised_user_bookmarks_handler.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using Folder
= SupervisedUserBookmarksHandler::Folder
;
19 using Link
= SupervisedUserBookmarksHandler::Link
;
23 typedef std::pair
<std::string
, std::string
> Setting
;
25 // Settings representing the following tree:
28 // |--Empty SubSubFolder
29 // |--Google(google.com)
30 // |--(www.theoatmeal.com)
31 // |--Test(www.test.de)
33 // |--XKCD(m.xkcd.com)
35 // Folder setting format: "<ID>", "<ParentID>:<Name>"
36 const Setting FOLDER_SETTINGS
[] = {
37 Setting("5", "0:Folder1"),
38 Setting("9", "0:Empty Folder"),
39 Setting("3", "5:SubFolder"),
40 Setting("4", "3:Empty SubSubFolder"),
43 const Setting FOLDER_SETTINGS_INVALID_PARENT
[] = {
44 Setting("5", "0:Folder1"),
45 Setting("9", "7:Empty Folder"), // Invalid parent id.
46 Setting("3", "5:SubFolder"),
47 Setting("4", "3:Empty SubSubFolder"),
50 const Setting FOLDER_SETTINGS_CIRCLE
[] = {
51 Setting("5", "3:Folder1"),
52 Setting("9", "5:Empty Folder"),
53 Setting("3", "9:SubFolder"),
56 // Link setting format: "<ID>:<URL>", "<ParentID>:<Name>"
57 const Setting LINK_SETTINGS
[] = {
58 Setting("4:www.theoatmeal.com", "3:"),
59 Setting("1:m.xkcd.com", "0:XKCD"),
60 Setting("2:www.test.de", "5:Test"),
61 Setting("3:google.com", "3:Google"),
64 const Setting LINK_SETTINGS_INVALID_PARENT
[] = {
65 Setting("4:www.theoatmeal.com", "3:"),
66 Setting("1:m.xkcd.com", "7:XKCD"), // Invalid parent id.
67 Setting("2:www.test.de", "8:Test"), // Invalid parent id.
70 // Parsed data is sorted by ID (even though the parsed links don't actually
71 // contain their IDs!)
73 const Folder PARSED_FOLDERS
[] = {
74 Folder(3, "SubFolder", 5), // Note: Forward reference.
75 Folder(4, "Empty SubSubFolder", 3),
76 Folder(5, "Folder1", 0),
77 Folder(9, "Empty Folder", 0),
80 const Link PARSED_LINKS
[] = {
81 Link("m.xkcd.com", "XKCD", 0),
82 Link("www.test.de", "Test", 5),
83 Link("google.com", "Google", 3),
84 Link("www.theoatmeal.com", std::string(), 3),
87 const char BOOKMARKS_TREE_JSON
[] =
91 " \"name\":\"Folder1\","
95 " \"name\":\"SubFolder\","
99 " \"name\":\"Empty SubSubFolder\","
103 " \"name\":\"Google\","
104 " \"url\":\"http://google.com/\""
108 " \"url\":\"http://www.theoatmeal.com/\""
113 " \"name\":\"Test\","
114 " \"url\":\"http://www.test.de/\""
120 " \"name\":\"Empty Folder\","
124 " \"name\":\"XKCD\","
125 " \"url\":\"http://m.xkcd.com/\""
129 const char BOOKMARKS_TREE_INVALID_PARENTS_JSON
[] =
133 " \"name\":\"Folder1\","
137 " \"name\":\"SubFolder\","
141 " \"name\":\"Empty SubSubFolder\","
146 " \"url\":\"http://www.theoatmeal.com/\""
154 // Builds the base::Values tree from a json string above.
155 scoped_ptr
<base::ListValue
> CreateTree(const char* json
) {
156 scoped_ptr
<base::Value
> value
= base::JSONReader::Read(json
);
157 EXPECT_NE(value
.get(), nullptr);
158 base::ListValue
* list
;
159 EXPECT_TRUE(value
->GetAsList(&list
));
160 ignore_result(value
.release());
161 return make_scoped_ptr(list
);
164 scoped_ptr
<base::ListValue
> CreateBookmarksTree() {
165 return CreateTree(BOOKMARKS_TREE_JSON
);
168 scoped_ptr
<base::ListValue
> CreateBookmarksTreeWithInvalidParents() {
169 return CreateTree(BOOKMARKS_TREE_INVALID_PARENTS_JSON
);
174 static bool operator==(const Folder
& f1
, const Folder
& f2
) {
175 return f1
.id
== f2
.id
&& f1
.name
== f2
.name
&& f1
.parent_id
== f2
.parent_id
;
178 static bool operator==(const Link
& l1
, const Link
& l2
) {
179 return l1
.url
== l2
.url
&& l1
.name
== l2
.name
&& l1
.parent_id
== l2
.parent_id
;
182 std::ostream
& operator<<(std::ostream
& str
, const Folder
& folder
) {
183 str
<< folder
.id
<< " " << folder
.name
<< " " << folder
.parent_id
;
187 std::ostream
& operator<<(std::ostream
& str
, const Link
& link
) {
188 str
<< link
.url
<< " " << link
.name
<< " " << link
.parent_id
;
192 class SupervisedUserBookmarksHandlerTest
: public ::testing::Test
{
194 static base::DictionaryValue
* CreateSettings(base::DictionaryValue
* links
,
195 base::DictionaryValue
* folders
) {
196 base::DictionaryValue
* settings
= new base::DictionaryValue
;
197 settings
->SetStringWithoutPathExpansion("some_setting", "bleh");
198 settings
->SetWithoutPathExpansion("SupervisedBookmarkLink", links
);
199 settings
->SetStringWithoutPathExpansion("some_other_setting", "foo");
200 settings
->SetWithoutPathExpansion("SupervisedBookmarkFolder", folders
);
201 settings
->SetStringWithoutPathExpansion("another_one", "blurb");
205 static base::DictionaryValue
* CreateDictionary(const Setting
* begin
,
206 const Setting
* end
) {
207 base::DictionaryValue
* dict
= new base::DictionaryValue
;
208 for (const Setting
* setting
= begin
; setting
!= end
; ++setting
)
209 dict
->SetStringWithoutPathExpansion(setting
->first
, setting
->second
);
213 static base::DictionaryValue
* CreateLinkDictionary() {
214 return CreateDictionary(LINK_SETTINGS
,
215 LINK_SETTINGS
+ arraysize(LINK_SETTINGS
));
218 static base::DictionaryValue
* CreateLinkDictionaryWithInvalidParents() {
219 return CreateDictionary(
220 LINK_SETTINGS_INVALID_PARENT
,
221 LINK_SETTINGS_INVALID_PARENT
+ arraysize(LINK_SETTINGS_INVALID_PARENT
));
224 static base::DictionaryValue
* CreateFolderDictionary() {
225 return CreateDictionary(FOLDER_SETTINGS
,
226 FOLDER_SETTINGS
+ arraysize(FOLDER_SETTINGS
));
229 static base::DictionaryValue
* CreateFolderDictionaryWithInvalidParents() {
230 return CreateDictionary(
231 FOLDER_SETTINGS_INVALID_PARENT
,
232 FOLDER_SETTINGS_INVALID_PARENT
+
233 arraysize(FOLDER_SETTINGS_INVALID_PARENT
));
236 static base::DictionaryValue
* CreateFolderDictionaryWithCircle() {
237 return CreateDictionary(
238 FOLDER_SETTINGS_CIRCLE
,
239 FOLDER_SETTINGS_CIRCLE
+ arraysize(FOLDER_SETTINGS_CIRCLE
));
242 void ParseFolders(const base::DictionaryValue
& folders
) {
243 deserializer_
.ParseFolders(folders
);
246 void ParseLinks(const base::DictionaryValue
& links
) {
247 deserializer_
.ParseLinks(links
);
250 const std::vector
<Folder
>& GetFolders() const {
251 return deserializer_
.folders_for_testing();
254 const std::vector
<Link
>& GetLinks() const {
255 return deserializer_
.links_for_testing();
259 SupervisedUserBookmarksHandler deserializer_
;
262 TEST_F(SupervisedUserBookmarksHandlerTest
, ParseSettings
) {
263 scoped_ptr
<base::DictionaryValue
> link_dictionary(CreateLinkDictionary());
264 scoped_ptr
<base::DictionaryValue
> folder_dictionary(CreateFolderDictionary());
266 ParseLinks(*link_dictionary
.get());
267 ParseFolders(*folder_dictionary
.get());
269 const std::vector
<Link
>& links
= GetLinks();
270 EXPECT_EQ(arraysize(PARSED_LINKS
), links
.size());
271 for (size_t i
= 0; i
< links
.size(); ++i
)
272 EXPECT_EQ(PARSED_LINKS
[i
], links
[i
]);
274 const std::vector
<Folder
>& folders
= GetFolders();
275 EXPECT_EQ(arraysize(PARSED_FOLDERS
), folders
.size());
276 for (size_t i
= 0; i
< folders
.size(); ++i
)
277 EXPECT_EQ(PARSED_FOLDERS
[i
], folders
[i
]);
280 TEST_F(SupervisedUserBookmarksHandlerTest
, BuildBookmarksTree
) {
281 // Make some fake settings.
282 scoped_ptr
<base::DictionaryValue
> settings(
283 CreateSettings(CreateLinkDictionary(), CreateFolderDictionary()));
284 // Parse the settings into a bookmarks tree.
285 scoped_ptr
<base::ListValue
> bookmarks(
286 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings
.get()));
288 // Check that the parsed tree matches the expected tree constructed directly
289 // from the hardcoded json above.
290 scoped_ptr
<base::ListValue
> expected_bookmarks(CreateBookmarksTree());
291 EXPECT_TRUE(bookmarks
->Equals(expected_bookmarks
.get()));
294 TEST_F(SupervisedUserBookmarksHandlerTest
,
295 BuildBookmarksTreeWithInvalidParents
) {
296 // Make some fake settings, including some entries with invalid parent
298 scoped_ptr
<base::DictionaryValue
> settings(
299 CreateSettings(CreateLinkDictionaryWithInvalidParents(),
300 CreateFolderDictionaryWithInvalidParents()));
301 // Parse the settings into a bookmarks tree.
302 scoped_ptr
<base::ListValue
> bookmarks(
303 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings
.get()));
305 // Check that the parsed tree matches the expected tree constructed directly
306 // from the hardcoded json above (which does not contain the entries with
307 // invalid parents!).
308 scoped_ptr
<base::ListValue
> expected_bookmarks(
309 CreateBookmarksTreeWithInvalidParents());
310 EXPECT_TRUE(bookmarks
->Equals(expected_bookmarks
.get()));
313 TEST_F(SupervisedUserBookmarksHandlerTest
, Circle
) {
314 // Make some fake settings which include a circular reference in the folders.
315 scoped_ptr
<base::DictionaryValue
> settings(
316 CreateSettings(CreateLinkDictionary(),
317 CreateFolderDictionaryWithCircle()));
318 scoped_ptr
<base::ListValue
> bookmarks(
319 SupervisedUserBookmarksHandler::BuildBookmarksTree(*settings
.get()));
320 // Don't care what exactly the result looks like, just that we don't run into