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
3// found in the LICENSE file.
4
5#include "base/basictypes.h"
6#include "base/files/scoped_temp_dir.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/string16.h"
9#include "base/strings/utf_string_conversions.h"
10#include "components/bookmarks/browser/bookmark_model.h"
11#include "components/bookmarks/browser/bookmark_node_data.h"
12#include "components/bookmarks/test/bookmark_test_helpers.h"
13#include "components/bookmarks/test/test_bookmark_client.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "ui/base/dragdrop/os_exchange_data.h"
16#include "ui/events/platform/platform_event_source.h"
17#include "url/gurl.h"
18
19using base::ASCIIToUTF16;
20
21namespace bookmarks {
22
23class BookmarkNodeDataTest : public testing::Test {
24 public:
25  BookmarkNodeDataTest() {}
26
27  virtual void SetUp() OVERRIDE {
28    event_source_ = ui::PlatformEventSource::CreateDefault();
29    model_ = client_.CreateModel();
30    test::WaitForBookmarkModelToLoad(model_.get());
31    bool success = profile_dir_.CreateUniqueTempDir();
32    ASSERT_TRUE(success);
33  }
34
35  virtual void TearDown() OVERRIDE {
36    model_.reset();
37    event_source_.reset();
38    bool success = profile_dir_.Delete();
39    ASSERT_TRUE(success);
40  }
41
42  const base::FilePath& GetProfilePath() const { return profile_dir_.path(); }
43
44  BookmarkModel* model() { return model_.get(); }
45
46 private:
47  base::ScopedTempDir profile_dir_;
48  TestBookmarkClient client_;
49  scoped_ptr<BookmarkModel> model_;
50  scoped_ptr<ui::PlatformEventSource> event_source_;
51
52  DISALLOW_COPY_AND_ASSIGN(BookmarkNodeDataTest);
53};
54
55namespace {
56
57ui::OSExchangeData::Provider* CloneProvider(const ui::OSExchangeData& data) {
58  return data.provider().Clone();
59}
60
61}  // namespace
62
63// Makes sure BookmarkNodeData is initially invalid.
64TEST_F(BookmarkNodeDataTest, InitialState) {
65  BookmarkNodeData data;
66  EXPECT_FALSE(data.is_valid());
67}
68
69// Makes sure reading bogus data leaves the BookmarkNodeData invalid.
70TEST_F(BookmarkNodeDataTest, BogusRead) {
71  ui::OSExchangeData data;
72  BookmarkNodeData drag_data;
73  EXPECT_FALSE(drag_data.Read(ui::OSExchangeData(CloneProvider(data))));
74  EXPECT_FALSE(drag_data.is_valid());
75}
76
77// Writes a URL to the clipboard and make sure BookmarkNodeData can correctly
78// read it.
79TEST_F(BookmarkNodeDataTest, JustURL) {
80  const GURL url("http://google.com");
81  const base::string16 title(ASCIIToUTF16("google.com"));
82
83  ui::OSExchangeData data;
84  data.SetURL(url, title);
85
86  BookmarkNodeData drag_data;
87  EXPECT_TRUE(drag_data.Read(ui::OSExchangeData(CloneProvider(data))));
88  EXPECT_TRUE(drag_data.is_valid());
89  ASSERT_EQ(1u, drag_data.elements.size());
90  EXPECT_TRUE(drag_data.elements[0].is_url);
91  EXPECT_EQ(url, drag_data.elements[0].url);
92  EXPECT_EQ(title, drag_data.elements[0].title);
93  EXPECT_TRUE(drag_data.elements[0].date_added.is_null());
94  EXPECT_TRUE(drag_data.elements[0].date_folder_modified.is_null());
95  EXPECT_EQ(0u, drag_data.elements[0].children.size());
96}
97
98TEST_F(BookmarkNodeDataTest, URL) {
99  // Write a single node representing a URL to the clipboard.
100  const BookmarkNode* root = model()->bookmark_bar_node();
101  GURL url(GURL("http://foo.com"));
102  const base::string16 title(ASCIIToUTF16("foo.com"));
103  const BookmarkNode* node = model()->AddURL(root, 0, title, url);
104  BookmarkNodeData drag_data(node);
105  EXPECT_TRUE(drag_data.is_valid());
106  ASSERT_EQ(1u, drag_data.elements.size());
107  EXPECT_TRUE(drag_data.elements[0].is_url);
108  EXPECT_EQ(url, drag_data.elements[0].url);
109  EXPECT_EQ(title, drag_data.elements[0].title);
110  EXPECT_EQ(node->date_added(), drag_data.elements[0].date_added);
111  EXPECT_EQ(node->date_folder_modified(),
112            drag_data.elements[0].date_folder_modified);
113  ui::OSExchangeData data;
114  drag_data.Write(GetProfilePath(), &data);
115
116  // Now read the data back in.
117  ui::OSExchangeData data2(CloneProvider(data));
118  BookmarkNodeData read_data;
119  EXPECT_TRUE(read_data.Read(data2));
120  EXPECT_TRUE(read_data.is_valid());
121  ASSERT_EQ(1u, read_data.elements.size());
122  EXPECT_TRUE(read_data.elements[0].is_url);
123  EXPECT_EQ(url, read_data.elements[0].url);
124  EXPECT_EQ(title, read_data.elements[0].title);
125  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
126  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
127  EXPECT_TRUE(read_data.GetFirstNode(model(), GetProfilePath()) == node);
128
129  // Make sure asking for the node with a different profile returns NULL.
130  base::ScopedTempDir other_profile_dir;
131  EXPECT_TRUE(other_profile_dir.CreateUniqueTempDir());
132  EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.path()) ==
133              NULL);
134
135  // Writing should also put the URL and title on the clipboard.
136  GURL read_url;
137  base::string16 read_title;
138  EXPECT_TRUE(data2.GetURLAndTitle(
139      ui::OSExchangeData::CONVERT_FILENAMES, &read_url, &read_title));
140  EXPECT_EQ(url, read_url);
141  EXPECT_EQ(title, read_title);
142}
143
144// Tests writing a folder to the clipboard.
145TEST_F(BookmarkNodeDataTest, Folder) {
146  const BookmarkNode* root = model()->bookmark_bar_node();
147  const BookmarkNode* g1 = model()->AddFolder(root, 0, ASCIIToUTF16("g1"));
148  model()->AddFolder(g1, 0, ASCIIToUTF16("g11"));
149  const BookmarkNode* g12 = model()->AddFolder(g1, 0, ASCIIToUTF16("g12"));
150
151  BookmarkNodeData drag_data(g12);
152  EXPECT_TRUE(drag_data.is_valid());
153  ASSERT_EQ(1u, drag_data.elements.size());
154  EXPECT_EQ(g12->GetTitle(), drag_data.elements[0].title);
155  EXPECT_FALSE(drag_data.elements[0].is_url);
156  EXPECT_EQ(g12->date_added(), drag_data.elements[0].date_added);
157  EXPECT_EQ(g12->date_folder_modified(),
158            drag_data.elements[0].date_folder_modified);
159
160  ui::OSExchangeData data;
161  drag_data.Write(GetProfilePath(), &data);
162
163  // Now read the data back in.
164  ui::OSExchangeData data2(CloneProvider(data));
165  BookmarkNodeData read_data;
166  EXPECT_TRUE(read_data.Read(data2));
167  EXPECT_TRUE(read_data.is_valid());
168  ASSERT_EQ(1u, read_data.elements.size());
169  EXPECT_EQ(g12->GetTitle(), read_data.elements[0].title);
170  EXPECT_FALSE(read_data.elements[0].is_url);
171  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
172  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
173
174  // We should get back the same node when asking for the same profile.
175  const BookmarkNode* r_g12 = read_data.GetFirstNode(model(), GetProfilePath());
176  EXPECT_TRUE(g12 == r_g12);
177
178  // A different profile should return NULL for the node.
179  base::ScopedTempDir other_profile_dir;
180  EXPECT_TRUE(other_profile_dir.CreateUniqueTempDir());
181  EXPECT_TRUE(read_data.GetFirstNode(model(), other_profile_dir.path()) ==
182              NULL);
183}
184
185// Tests reading/writing a folder with children.
186TEST_F(BookmarkNodeDataTest, FolderWithChild) {
187  const BookmarkNode* root = model()->bookmark_bar_node();
188  const BookmarkNode* folder = model()->AddFolder(root, 0, ASCIIToUTF16("g1"));
189
190  GURL url(GURL("http://foo.com"));
191  const base::string16 title(ASCIIToUTF16("blah2"));
192
193  model()->AddURL(folder, 0, title, url);
194
195  BookmarkNodeData drag_data(folder);
196
197  ui::OSExchangeData data;
198  drag_data.Write(GetProfilePath(), &data);
199
200  // Now read the data back in.
201  ui::OSExchangeData data2(CloneProvider(data));
202  BookmarkNodeData read_data;
203  EXPECT_TRUE(read_data.Read(data2));
204  ASSERT_EQ(1u, read_data.elements.size());
205  ASSERT_EQ(1u, read_data.elements[0].children.size());
206  const BookmarkNodeData::Element& read_child =
207      read_data.elements[0].children[0];
208
209  EXPECT_TRUE(read_child.is_url);
210  EXPECT_EQ(title, read_child.title);
211  EXPECT_EQ(url, read_child.url);
212  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
213  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
214  EXPECT_TRUE(read_child.is_url);
215
216  // And make sure we get the node back.
217  const BookmarkNode* r_folder =
218      read_data.GetFirstNode(model(), GetProfilePath());
219  EXPECT_TRUE(folder == r_folder);
220}
221
222// Tests reading/writing of multiple nodes.
223TEST_F(BookmarkNodeDataTest, MultipleNodes) {
224  const BookmarkNode* root = model()->bookmark_bar_node();
225  const BookmarkNode* folder = model()->AddFolder(root, 0, ASCIIToUTF16("g1"));
226
227  GURL url(GURL("http://foo.com"));
228  const base::string16 title(ASCIIToUTF16("blah2"));
229
230  const BookmarkNode* url_node = model()->AddURL(folder, 0, title, url);
231
232  // Write the nodes to the clipboard.
233  std::vector<const BookmarkNode*> nodes;
234  nodes.push_back(folder);
235  nodes.push_back(url_node);
236  BookmarkNodeData drag_data(nodes);
237  ui::OSExchangeData data;
238  drag_data.Write(GetProfilePath(), &data);
239
240  // Read the data back in.
241  ui::OSExchangeData data2(CloneProvider(data));
242  BookmarkNodeData read_data;
243  EXPECT_TRUE(read_data.Read(data2));
244  EXPECT_TRUE(read_data.is_valid());
245  ASSERT_EQ(2u, read_data.elements.size());
246  ASSERT_EQ(1u, read_data.elements[0].children.size());
247  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
248  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
249
250  const BookmarkNodeData::Element& read_folder = read_data.elements[0];
251  EXPECT_FALSE(read_folder.is_url);
252  EXPECT_EQ(ASCIIToUTF16("g1"), read_folder.title);
253  EXPECT_EQ(1u, read_folder.children.size());
254
255  const BookmarkNodeData::Element& read_url = read_data.elements[1];
256  EXPECT_TRUE(read_url.is_url);
257  EXPECT_EQ(title, read_url.title);
258  EXPECT_EQ(0u, read_url.children.size());
259
260  // And make sure we get the node back.
261  std::vector<const BookmarkNode*> read_nodes =
262      read_data.GetNodes(model(), GetProfilePath());
263  ASSERT_EQ(2u, read_nodes.size());
264  EXPECT_TRUE(read_nodes[0] == folder);
265  EXPECT_TRUE(read_nodes[1] == url_node);
266
267  // Asking for the first node should return NULL with more than one element
268  // present.
269  EXPECT_TRUE(read_data.GetFirstNode(model(), GetProfilePath()) == NULL);
270}
271
272// Tests reading/writing of meta info.
273TEST_F(BookmarkNodeDataTest, MetaInfo) {
274  // Create a node containing meta info.
275  const BookmarkNode* node = model()->AddURL(model()->other_node(),
276                                             0,
277                                             ASCIIToUTF16("foo bar"),
278                                             GURL("http://www.google.com"));
279  model()->SetNodeMetaInfo(node, "somekey", "somevalue");
280  model()->SetNodeMetaInfo(node, "someotherkey", "someothervalue");
281
282  BookmarkNodeData node_data(node);
283  ui::OSExchangeData data;
284  node_data.Write(GetProfilePath(), &data);
285
286  // Read the data back in.
287  ui::OSExchangeData data2(CloneProvider(data));
288  BookmarkNodeData read_data;
289  EXPECT_TRUE(read_data.Read(data2));
290  EXPECT_TRUE(read_data.is_valid());
291  ASSERT_EQ(1u, read_data.elements.size());
292
293  // Verify that the read data contains the same meta info.
294  BookmarkNode::MetaInfoMap meta_info_map = read_data.elements[0].meta_info_map;
295  EXPECT_EQ(2u, meta_info_map.size());
296  EXPECT_EQ("somevalue", meta_info_map["somekey"]);
297  EXPECT_EQ("someothervalue", meta_info_map["someotherkey"]);
298}
299
300}  // namespace bookmarks
301