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/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"
17 using Folder
= SupervisedUserBookmarksHandler::Folder
;
18 using Link
= SupervisedUserBookmarksHandler::Link
;
22 typedef std::pair
<std::string
, std::string
> Setting
;
24 // Settings representing the following tree:
27 // |--Empty SubSubFolder
28 // |--Google(google.com)
29 // |--(www.theoatmeal.com)
30 // |--Test(www.test.de)
32 // |--XKCD(m.xkcd.com)
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"),
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"),
49 const Setting FOLDER_SETTINGS_CIRCLE
[] = {
50 Setting("5", "3:Folder1"),
51 Setting("9", "5:Empty Folder"),
52 Setting("3", "9:SubFolder"),
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"),
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.
69 // Parsed data is sorted by ID (even though the parsed links don't actually
70 // contain their IDs!)
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),
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),
86 const char BOOKMARKS_TREE_JSON
[] =
90 " \"name\":\"Folder1\","
94 " \"name\":\"SubFolder\","
98 " \"name\":\"Empty SubSubFolder\","
102 " \"name\":\"Google\","
103 " \"url\":\"http://google.com/\""
107 " \"url\":\"http://www.theoatmeal.com/\""
112 " \"name\":\"Test\","
113 " \"url\":\"http://www.test.de/\""
119 " \"name\":\"Empty Folder\","
123 " \"name\":\"XKCD\","
124 " \"url\":\"http://m.xkcd.com/\""
128 const char BOOKMARKS_TREE_INVALID_PARENTS_JSON
[] =
132 " \"name\":\"Folder1\","
136 " \"name\":\"SubFolder\","
140 " \"name\":\"Empty SubSubFolder\","
145 " \"url\":\"http://www.theoatmeal.com/\""
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::DeprecatedRead(json
);
156 EXPECT_NE(value
, nullptr);
157 base::ListValue
* list
;
158 EXPECT_TRUE(value
->GetAsList(&list
));
159 return make_scoped_ptr(list
);
162 scoped_ptr
<base::ListValue
> CreateBookmarksTree() {
163 return CreateTree(BOOKMARKS_TREE_JSON
);
166 scoped_ptr
<base::ListValue
> CreateBookmarksTreeWithInvalidParents() {
167 return CreateTree(BOOKMARKS_TREE_INVALID_PARENTS_JSON
);
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
;
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
;
180 std::ostream
& operator<<(std::ostream
& str
, const Folder
& folder
) {
181 str
<< folder
.id
<< " " << folder
.name
<< " " << folder
.parent_id
;
185 std::ostream
& operator<<(std::ostream
& str
, const Link
& link
) {
186 str
<< link
.url
<< " " << link
.name
<< " " << link
.parent_id
;
190 class SupervisedUserBookmarksHandlerTest
: public ::testing::Test
{
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");
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
);
211 static base::DictionaryValue
* CreateLinkDictionary() {
212 return CreateDictionary(LINK_SETTINGS
,
213 LINK_SETTINGS
+ arraysize(LINK_SETTINGS
));
216 static base::DictionaryValue
* CreateLinkDictionaryWithInvalidParents() {
217 return CreateDictionary(
218 LINK_SETTINGS_INVALID_PARENT
,
219 LINK_SETTINGS_INVALID_PARENT
+ arraysize(LINK_SETTINGS_INVALID_PARENT
));
222 static base::DictionaryValue
* CreateFolderDictionary() {
223 return CreateDictionary(FOLDER_SETTINGS
,
224 FOLDER_SETTINGS
+ arraysize(FOLDER_SETTINGS
));
227 static base::DictionaryValue
* CreateFolderDictionaryWithInvalidParents() {
228 return CreateDictionary(
229 FOLDER_SETTINGS_INVALID_PARENT
,
230 FOLDER_SETTINGS_INVALID_PARENT
+
231 arraysize(FOLDER_SETTINGS_INVALID_PARENT
));
234 static base::DictionaryValue
* CreateFolderDictionaryWithCircle() {
235 return CreateDictionary(
236 FOLDER_SETTINGS_CIRCLE
,
237 FOLDER_SETTINGS_CIRCLE
+ arraysize(FOLDER_SETTINGS_CIRCLE
));
240 void ParseFolders(const base::DictionaryValue
& folders
) {
241 deserializer_
.ParseFolders(folders
);
244 void ParseLinks(const base::DictionaryValue
& links
) {
245 deserializer_
.ParseLinks(links
);
248 const std::vector
<Folder
>& GetFolders() const {
249 return deserializer_
.folders_for_testing();
252 const std::vector
<Link
>& GetLinks() const {
253 return deserializer_
.links_for_testing();
257 SupervisedUserBookmarksHandler deserializer_
;
260 TEST_F(SupervisedUserBookmarksHandlerTest
, ParseSettings
) {
261 scoped_ptr
<base::DictionaryValue
> link_dictionary(CreateLinkDictionary());
262 scoped_ptr
<base::DictionaryValue
> folder_dictionary(CreateFolderDictionary());
264 ParseLinks(*link_dictionary
.get());
265 ParseFolders(*folder_dictionary
.get());
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
]);
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
]);
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()));
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()));
292 TEST_F(SupervisedUserBookmarksHandlerTest
,
293 BuildBookmarksTreeWithInvalidParents
) {
294 // Make some fake settings, including some entries with invalid parent
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()));
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()));
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