OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "components/bookmarks/core/browser/bookmark_utils.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/message_loop/message_loop.h" | |
10 #include "base/strings/utf_string_conversions.h" | |
11 #include "components/bookmarks/core/browser/base_bookmark_model_observer.h" | |
12 #include "components/bookmarks/core/browser/bookmark_model.h" | |
13 #include "components/bookmarks/core/browser/bookmark_node_data.h" | |
14 #include "components/bookmarks/core/test/test_bookmark_client.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 #include "ui/base/clipboard/clipboard.h" | |
17 #include "ui/base/clipboard/scoped_clipboard_writer.h" | |
18 | |
19 using base::ASCIIToUTF16; | |
20 using std::string; | |
21 | |
22 namespace bookmark_utils { | |
23 namespace { | |
24 | |
25 class BookmarkUtilsTest : public testing::Test, | |
26 public BaseBookmarkModelObserver { | |
27 public: | |
28 BookmarkUtilsTest() | |
29 : grouped_changes_beginning_count_(0), | |
30 grouped_changes_ended_count_(0) {} | |
31 virtual ~BookmarkUtilsTest() {} | |
32 | |
33 // Copy and paste is not yet supported on iOS. http://crbug.com/228147 | |
34 #if !defined(OS_IOS) | |
35 virtual void TearDown() OVERRIDE { | |
36 ui::Clipboard::DestroyClipboardForCurrentThread(); | |
37 } | |
38 #endif // !defined(OS_IOS) | |
39 | |
40 // Certain user actions require multiple changes to the bookmark model, | |
41 // however these modifications need to be atomic for the undo framework. The | |
42 // BaseBookmarkModelObserver is used to inform the boundaries of the user | |
43 // action. For example, when multiple bookmarks are cut to the clipboard we | |
44 // expect one call each to GroupedBookmarkChangesBeginning/Ended. | |
45 void ExpectGroupedChangeCount(int expected_beginning_count, | |
46 int expected_ended_count) { | |
47 // The undo framework is not used under Android. Thus the group change | |
48 // events will not be fired and so should not be tested for Android. | |
49 #if !defined(OS_ANDROID) | |
50 EXPECT_EQ(grouped_changes_beginning_count_, expected_beginning_count); | |
51 EXPECT_EQ(grouped_changes_ended_count_, expected_ended_count); | |
52 #endif | |
53 } | |
54 | |
55 private: | |
56 // BaseBookmarkModelObserver: | |
57 virtual void BookmarkModelChanged() OVERRIDE {} | |
58 | |
59 virtual void GroupedBookmarkChangesBeginning(BookmarkModel* model) OVERRIDE { | |
60 ++grouped_changes_beginning_count_; | |
61 } | |
62 | |
63 virtual void GroupedBookmarkChangesEnded(BookmarkModel* model) OVERRIDE { | |
64 ++grouped_changes_ended_count_; | |
65 } | |
66 | |
67 int grouped_changes_beginning_count_; | |
68 int grouped_changes_ended_count_; | |
69 | |
70 // Clipboard requires a message loop. | |
71 base::MessageLoopForUI loop_; | |
72 | |
73 DISALLOW_COPY_AND_ASSIGN(BookmarkUtilsTest); | |
74 }; | |
75 | |
76 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesWordPhraseQuery) { | |
77 test::TestBookmarkClient client; | |
78 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
79 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
80 0, | |
81 ASCIIToUTF16("foo bar"), | |
82 GURL("http://www.google.com")); | |
83 const BookmarkNode* node2 = model->AddURL(model->other_node(), | |
84 0, | |
85 ASCIIToUTF16("baz buz"), | |
86 GURL("http://www.cnn.com")); | |
87 const BookmarkNode* folder1 = | |
88 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("foo")); | |
89 std::vector<const BookmarkNode*> nodes; | |
90 QueryFields query; | |
91 query.word_phrase_query.reset(new base::string16); | |
92 // No nodes are returned for empty string. | |
93 *query.word_phrase_query = ASCIIToUTF16(""); | |
94 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
95 EXPECT_TRUE(nodes.empty()); | |
96 nodes.clear(); | |
97 | |
98 // No nodes are returned for space-only string. | |
99 *query.word_phrase_query = ASCIIToUTF16(" "); | |
100 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
101 EXPECT_TRUE(nodes.empty()); | |
102 nodes.clear(); | |
103 | |
104 // Node "foo bar" and folder "foo" are returned in search results. | |
105 *query.word_phrase_query = ASCIIToUTF16("foo"); | |
106 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
107 ASSERT_EQ(2U, nodes.size()); | |
108 EXPECT_TRUE(nodes[0] == folder1); | |
109 EXPECT_TRUE(nodes[1] == node1); | |
110 nodes.clear(); | |
111 | |
112 // Ensure url matches return in search results. | |
113 *query.word_phrase_query = ASCIIToUTF16("cnn"); | |
114 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
115 ASSERT_EQ(1U, nodes.size()); | |
116 EXPECT_TRUE(nodes[0] == node2); | |
117 nodes.clear(); | |
118 | |
119 // Ensure folder "foo" is not returned in more specific search. | |
120 *query.word_phrase_query = ASCIIToUTF16("foo bar"); | |
121 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
122 ASSERT_EQ(1U, nodes.size()); | |
123 EXPECT_TRUE(nodes[0] == node1); | |
124 nodes.clear(); | |
125 | |
126 // Bookmark Bar and Other Bookmarks are not returned in search results. | |
127 *query.word_phrase_query = ASCIIToUTF16("Bookmark"); | |
128 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
129 ASSERT_EQ(0U, nodes.size()); | |
130 nodes.clear(); | |
131 } | |
132 | |
133 // Check exact matching against a URL query. | |
134 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesUrl) { | |
135 test::TestBookmarkClient client; | |
136 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
137 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
138 0, | |
139 ASCIIToUTF16("Google"), | |
140 GURL("https://www.google.com/")); | |
141 model->AddURL(model->other_node(), | |
142 0, | |
143 ASCIIToUTF16("Google Calendar"), | |
144 GURL("https://www.google.com/calendar")); | |
145 | |
146 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
147 | |
148 std::vector<const BookmarkNode*> nodes; | |
149 QueryFields query; | |
150 query.url.reset(new base::string16); | |
151 *query.url = ASCIIToUTF16("https://www.google.com/"); | |
152 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
153 ASSERT_EQ(1U, nodes.size()); | |
154 EXPECT_TRUE(nodes[0] == node1); | |
155 nodes.clear(); | |
156 | |
157 *query.url = ASCIIToUTF16("calendar"); | |
158 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
159 ASSERT_EQ(0U, nodes.size()); | |
160 nodes.clear(); | |
161 | |
162 // Empty URL should not match folders. | |
163 *query.url = ASCIIToUTF16(""); | |
164 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
165 ASSERT_EQ(0U, nodes.size()); | |
166 nodes.clear(); | |
167 } | |
168 | |
169 // Check exact matching against a title query. | |
170 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesTitle) { | |
171 test::TestBookmarkClient client; | |
172 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
173 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
174 0, | |
175 ASCIIToUTF16("Google"), | |
176 GURL("https://www.google.com/")); | |
177 model->AddURL(model->other_node(), | |
178 0, | |
179 ASCIIToUTF16("Google Calendar"), | |
180 GURL("https://www.google.com/calendar")); | |
181 | |
182 const BookmarkNode* folder1 = | |
183 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
184 | |
185 std::vector<const BookmarkNode*> nodes; | |
186 QueryFields query; | |
187 query.title.reset(new base::string16); | |
188 *query.title = ASCIIToUTF16("Google"); | |
189 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
190 ASSERT_EQ(1U, nodes.size()); | |
191 EXPECT_TRUE(nodes[0] == node1); | |
192 nodes.clear(); | |
193 | |
194 *query.title = ASCIIToUTF16("Calendar"); | |
195 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
196 ASSERT_EQ(0U, nodes.size()); | |
197 nodes.clear(); | |
198 | |
199 // Title should match folders. | |
200 *query.title = ASCIIToUTF16("Folder"); | |
201 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
202 ASSERT_EQ(1U, nodes.size()); | |
203 EXPECT_TRUE(nodes[0] == folder1); | |
204 nodes.clear(); | |
205 } | |
206 | |
207 // Check matching against a query with multiple predicates. | |
208 TEST_F(BookmarkUtilsTest, GetBookmarksMatchingPropertiesConjunction) { | |
209 test::TestBookmarkClient client; | |
210 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
211 const BookmarkNode* node1 = model->AddURL(model->other_node(), | |
212 0, | |
213 ASCIIToUTF16("Google"), | |
214 GURL("https://www.google.com/")); | |
215 model->AddURL(model->other_node(), | |
216 0, | |
217 ASCIIToUTF16("Google Calendar"), | |
218 GURL("https://www.google.com/calendar")); | |
219 | |
220 model->AddFolder(model->other_node(), 0, ASCIIToUTF16("Folder")); | |
221 | |
222 std::vector<const BookmarkNode*> nodes; | |
223 QueryFields query; | |
224 | |
225 // Test all fields matching. | |
226 query.word_phrase_query.reset(new base::string16(ASCIIToUTF16("www"))); | |
227 query.url.reset(new base::string16(ASCIIToUTF16("https://www.google.com/"))); | |
228 query.title.reset(new base::string16(ASCIIToUTF16("Google"))); | |
229 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
230 ASSERT_EQ(1U, nodes.size()); | |
231 EXPECT_TRUE(nodes[0] == node1); | |
232 nodes.clear(); | |
233 | |
234 scoped_ptr<base::string16>* fields[] = { | |
235 &query.word_phrase_query, &query.url, &query.title }; | |
236 | |
237 // Test two fields matching. | |
238 for (size_t i = 0; i < arraysize(fields); i++) { | |
239 scoped_ptr<base::string16> original_value(fields[i]->release()); | |
240 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
241 ASSERT_EQ(1U, nodes.size()); | |
242 EXPECT_TRUE(nodes[0] == node1); | |
243 nodes.clear(); | |
244 fields[i]->reset(original_value.release()); | |
245 } | |
246 | |
247 // Test two fields matching with one non-matching field. | |
248 for (size_t i = 0; i < arraysize(fields); i++) { | |
249 scoped_ptr<base::string16> original_value(fields[i]->release()); | |
250 fields[i]->reset(new base::string16(ASCIIToUTF16("fjdkslafjkldsa"))); | |
251 GetBookmarksMatchingProperties(model.get(), query, 100, string(), &nodes); | |
252 ASSERT_EQ(0U, nodes.size()); | |
253 nodes.clear(); | |
254 fields[i]->reset(original_value.release()); | |
255 } | |
256 } | |
257 | |
258 // Copy and paste is not yet supported on iOS. http://crbug.com/228147 | |
259 #if !defined(OS_IOS) | |
260 TEST_F(BookmarkUtilsTest, CopyPaste) { | |
261 test::TestBookmarkClient client; | |
262 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
263 const BookmarkNode* node = model->AddURL(model->other_node(), | |
264 0, | |
265 ASCIIToUTF16("foo bar"), | |
266 GURL("http://www.google.com")); | |
267 | |
268 // Copy a node to the clipboard. | |
269 std::vector<const BookmarkNode*> nodes; | |
270 nodes.push_back(node); | |
271 CopyToClipboard(model.get(), nodes, false); | |
272 | |
273 // And make sure we can paste a bookmark from the clipboard. | |
274 EXPECT_TRUE(CanPasteFromClipboard(model->bookmark_bar_node())); | |
275 | |
276 // Write some text to the clipboard. | |
277 { | |
278 ui::ScopedClipboardWriter clipboard_writer( | |
279 ui::Clipboard::GetForCurrentThread(), | |
280 ui::CLIPBOARD_TYPE_COPY_PASTE); | |
281 clipboard_writer.WriteText(ASCIIToUTF16("foo")); | |
282 } | |
283 | |
284 // Now we shouldn't be able to paste from the clipboard. | |
285 EXPECT_FALSE(CanPasteFromClipboard(model->bookmark_bar_node())); | |
286 } | |
287 | |
288 TEST_F(BookmarkUtilsTest, CutToClipboard) { | |
289 test::TestBookmarkClient client; | |
290 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
291 model->AddObserver(this); | |
292 | |
293 base::string16 title(ASCIIToUTF16("foo")); | |
294 GURL url("http://foo.com"); | |
295 const BookmarkNode* n1 = model->AddURL(model->other_node(), 0, title, url); | |
296 const BookmarkNode* n2 = model->AddURL(model->other_node(), 1, title, url); | |
297 | |
298 // Cut the nodes to the clipboard. | |
299 std::vector<const BookmarkNode*> nodes; | |
300 nodes.push_back(n1); | |
301 nodes.push_back(n2); | |
302 CopyToClipboard(model.get(), nodes, true); | |
303 | |
304 // Make sure the nodes were removed. | |
305 EXPECT_EQ(0, model->other_node()->child_count()); | |
306 | |
307 // Make sure observers were notified the set of changes should be grouped. | |
308 ExpectGroupedChangeCount(1, 1); | |
309 | |
310 // And make sure we can paste from the clipboard. | |
311 EXPECT_TRUE(CanPasteFromClipboard(model->other_node())); | |
312 } | |
313 #endif // !defined(OS_IOS) | |
314 | |
315 TEST_F(BookmarkUtilsTest, GetParentForNewNodes) { | |
316 test::TestBookmarkClient client; | |
317 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
318 // This tests the case where selection contains one item and that item is a | |
319 // folder. | |
320 std::vector<const BookmarkNode*> nodes; | |
321 nodes.push_back(model->bookmark_bar_node()); | |
322 int index = -1; | |
323 const BookmarkNode* real_parent = | |
324 GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
325 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
326 EXPECT_EQ(0, index); | |
327 | |
328 nodes.clear(); | |
329 | |
330 // This tests the case where selection contains one item and that item is an | |
331 // url. | |
332 const BookmarkNode* page1 = model->AddURL(model->bookmark_bar_node(), | |
333 0, | |
334 ASCIIToUTF16("Google"), | |
335 GURL("http://google.com")); | |
336 nodes.push_back(page1); | |
337 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
338 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
339 EXPECT_EQ(1, index); | |
340 | |
341 // This tests the case where selection has more than one item. | |
342 const BookmarkNode* folder1 = | |
343 model->AddFolder(model->bookmark_bar_node(), 1, ASCIIToUTF16("Folder 1")); | |
344 nodes.push_back(folder1); | |
345 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
346 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
347 EXPECT_EQ(2, index); | |
348 | |
349 // This tests the case where selection doesn't contain any items. | |
350 nodes.clear(); | |
351 real_parent = GetParentForNewNodes(model->bookmark_bar_node(), nodes, &index); | |
352 EXPECT_EQ(real_parent, model->bookmark_bar_node()); | |
353 EXPECT_EQ(2, index); | |
354 } | |
355 | |
356 // Verifies that meta info is copied when nodes are cloned. | |
357 TEST_F(BookmarkUtilsTest, CloneMetaInfo) { | |
358 test::TestBookmarkClient client; | |
359 scoped_ptr<BookmarkModel> model(client.CreateModel(false)); | |
360 // Add a node containing meta info. | |
361 const BookmarkNode* node = model->AddURL(model->other_node(), | |
362 0, | |
363 ASCIIToUTF16("foo bar"), | |
364 GURL("http://www.google.com")); | |
365 model->SetNodeMetaInfo(node, "somekey", "somevalue"); | |
366 model->SetNodeMetaInfo(node, "someotherkey", "someothervalue"); | |
367 | |
368 // Clone node to a different folder. | |
369 const BookmarkNode* folder = | |
370 model->AddFolder(model->bookmark_bar_node(), 0, ASCIIToUTF16("Folder")); | |
371 std::vector<BookmarkNodeData::Element> elements; | |
372 BookmarkNodeData::Element node_data(node); | |
373 elements.push_back(node_data); | |
374 EXPECT_EQ(0, folder->child_count()); | |
375 CloneBookmarkNode(model.get(), elements, folder, 0, false); | |
376 ASSERT_EQ(1, folder->child_count()); | |
377 | |
378 // Verify that the cloned node contains the same meta info. | |
379 const BookmarkNode* clone = folder->GetChild(0); | |
380 ASSERT_TRUE(clone->GetMetaInfoMap()); | |
381 EXPECT_EQ(2u, clone->GetMetaInfoMap()->size()); | |
382 std::string value; | |
383 EXPECT_TRUE(clone->GetMetaInfo("somekey", &value)); | |
384 EXPECT_EQ("somevalue", value); | |
385 EXPECT_TRUE(clone->GetMetaInfo("someotherkey", &value)); | |
386 EXPECT_EQ("someothervalue", value); | |
387 } | |
388 | |
389 } // namespace | |
390 } // namespace bookmark_utils | |
OLD | NEW |