clipboard_unittest.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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 "build/build_config.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "base/pickle.h"
13#include "base/run_loop.h"
14#include "base/strings/string_util.h"
15#include "base/strings/utf_string_conversions.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "testing/platform_test.h"
18#include "third_party/skia/include/core/SkBitmap.h"
19#include "third_party/skia/include/core/SkColor.h"
20#include "third_party/skia/include/core/SkScalar.h"
21#include "third_party/skia/include/core/SkUnPreMultiply.h"
22#include "ui/base/clipboard/clipboard.h"
23#include "ui/base/clipboard/scoped_clipboard_writer.h"
24#include "ui/gfx/size.h"
25
26#if defined(OS_WIN)
27#include "ui/base/clipboard/clipboard_util_win.h"
28#endif
29
30#if defined(OS_ANDROID)
31#include "base/android/jni_android.h"
32#include "base/android/jni_string.h"
33#endif
34
35#if defined(USE_AURA)
36#include "ui/events/platform/platform_event_source.h"
37#endif
38
39using base::ASCIIToUTF16;
40using base::UTF8ToUTF16;
41using base::UTF16ToUTF8;
42
43namespace ui {
44
45class ClipboardTest : public PlatformTest {
46 public:
47#if defined(USE_AURA)
48  ClipboardTest() : event_source_(ui::PlatformEventSource::CreateDefault()) {}
49#else
50  ClipboardTest() {}
51#endif
52
53  static void WriteObjectsToClipboard(ui::Clipboard* clipboard,
54                                      const Clipboard::ObjectMap& objects) {
55    clipboard->WriteObjects(ui::CLIPBOARD_TYPE_COPY_PASTE, objects);
56  }
57
58 protected:
59  Clipboard& clipboard() { return clipboard_; }
60
61  void WriteObjectsToClipboard(const Clipboard::ObjectMap& objects) {
62    WriteObjectsToClipboard(&clipboard(), objects);
63  }
64
65 private:
66  base::MessageLoopForUI message_loop_;
67#if defined(USE_AURA)
68  scoped_ptr<PlatformEventSource> event_source_;
69#endif
70  Clipboard clipboard_;
71};
72
73namespace {
74
75bool MarkupMatches(const base::string16& expected_markup,
76                   const base::string16& actual_markup) {
77  return actual_markup.find(expected_markup) != base::string16::npos;
78}
79
80}  // namespace
81
82TEST_F(ClipboardTest, ClearTest) {
83  {
84    ScopedClipboardWriter clipboard_writer(&clipboard(),
85                                           CLIPBOARD_TYPE_COPY_PASTE);
86    clipboard_writer.WriteText(ASCIIToUTF16("clear me"));
87  }
88
89  clipboard().Clear(CLIPBOARD_TYPE_COPY_PASTE);
90
91  EXPECT_FALSE(clipboard().IsFormatAvailable(
92      Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
93  EXPECT_FALSE(clipboard().IsFormatAvailable(
94      Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
95}
96
97TEST_F(ClipboardTest, TextTest) {
98  base::string16 text(ASCIIToUTF16("This is a base::string16!#$")), text_result;
99  std::string ascii_text;
100
101  {
102    ScopedClipboardWriter clipboard_writer(&clipboard(),
103                                           CLIPBOARD_TYPE_COPY_PASTE);
104    clipboard_writer.WriteText(text);
105  }
106
107  EXPECT_TRUE(clipboard().IsFormatAvailable(
108      Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
109  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetPlainTextFormatType(),
110                                            CLIPBOARD_TYPE_COPY_PASTE));
111  clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
112
113  EXPECT_EQ(text, text_result);
114  clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text);
115  EXPECT_EQ(UTF16ToUTF8(text), ascii_text);
116}
117
118TEST_F(ClipboardTest, HTMLTest) {
119  base::string16 markup(ASCIIToUTF16("<string>Hi!</string>")), markup_result;
120  base::string16 plain(ASCIIToUTF16("Hi!")), plain_result;
121  std::string url("http://www.example.com/"), url_result;
122
123  {
124    ScopedClipboardWriter clipboard_writer(&clipboard(),
125                                           CLIPBOARD_TYPE_COPY_PASTE);
126    clipboard_writer.WriteText(plain);
127    clipboard_writer.WriteHTML(markup, url);
128  }
129
130  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
131                                            CLIPBOARD_TYPE_COPY_PASTE));
132  uint32 ignored;
133  clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, &url_result,
134                     &ignored, &ignored);
135  EXPECT_PRED2(MarkupMatches, markup, markup_result);
136#if defined(OS_WIN)
137  // TODO(playmobil): It's not clear that non windows clipboards need to support
138  // this.
139  EXPECT_EQ(url, url_result);
140#endif  // defined(OS_WIN)
141}
142
143TEST_F(ClipboardTest, RTFTest) {
144  std::string rtf =
145      "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\n"
146      "This is some {\\b bold} text.\\par\n"
147      "}";
148
149  {
150    ScopedClipboardWriter clipboard_writer(&clipboard(),
151                                           CLIPBOARD_TYPE_COPY_PASTE);
152    clipboard_writer.WriteRTF(rtf);
153  }
154
155  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetRtfFormatType(),
156                                            CLIPBOARD_TYPE_COPY_PASTE));
157  std::string result;
158  clipboard().ReadRTF(CLIPBOARD_TYPE_COPY_PASTE, &result);
159  EXPECT_EQ(rtf, result);
160}
161
162// TODO(dnicoara) Enable test once Ozone implements clipboard support:
163// crbug.com/361707
164#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
165TEST_F(ClipboardTest, MultipleBufferTest) {
166  base::string16 text(ASCIIToUTF16("Standard")), text_result;
167  base::string16 markup(ASCIIToUTF16("<string>Selection</string>"));
168  std::string url("http://www.example.com/"), url_result;
169
170  {
171    ScopedClipboardWriter clipboard_writer(&clipboard(),
172                                           CLIPBOARD_TYPE_COPY_PASTE);
173    clipboard_writer.WriteText(text);
174  }
175
176  {
177    ScopedClipboardWriter clipboard_writer(&clipboard(),
178                                           CLIPBOARD_TYPE_SELECTION);
179    clipboard_writer.WriteHTML(markup, url);
180  }
181
182  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetPlainTextFormatType(),
183                                            CLIPBOARD_TYPE_COPY_PASTE));
184  EXPECT_FALSE(clipboard().IsFormatAvailable(
185      Clipboard::GetPlainTextFormatType(),
186      CLIPBOARD_TYPE_SELECTION));
187
188  EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
189                                             CLIPBOARD_TYPE_COPY_PASTE));
190  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
191                                            CLIPBOARD_TYPE_SELECTION));
192
193  clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
194  EXPECT_EQ(text, text_result);
195
196  uint32 ignored;
197  base::string16 markup_result;
198  clipboard().ReadHTML(CLIPBOARD_TYPE_SELECTION,
199                       &markup_result,
200                       &url_result,
201                       &ignored,
202                       &ignored);
203  EXPECT_PRED2(MarkupMatches, markup, markup_result);
204}
205#endif
206
207TEST_F(ClipboardTest, TrickyHTMLTest) {
208  base::string16 markup(ASCIIToUTF16("<em>Bye!<!--EndFragment --></em>")),
209      markup_result;
210  std::string url, url_result;
211  base::string16 plain(ASCIIToUTF16("Bye!")), plain_result;
212
213  {
214    ScopedClipboardWriter clipboard_writer(&clipboard(),
215                                           CLIPBOARD_TYPE_COPY_PASTE);
216    clipboard_writer.WriteText(plain);
217    clipboard_writer.WriteHTML(markup, url);
218  }
219
220  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
221                                            CLIPBOARD_TYPE_COPY_PASTE));
222  uint32 ignored;
223  clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, &url_result,
224                       &ignored, &ignored);
225  EXPECT_PRED2(MarkupMatches, markup, markup_result);
226#if defined(OS_WIN)
227  // TODO(playmobil): It's not clear that non windows clipboards need to support
228  // this.
229  EXPECT_EQ(url, url_result);
230#endif  // defined(OS_WIN)
231}
232
233#if defined(OS_WIN)
234TEST_F(ClipboardTest, UniodeHTMLTest) {
235  base::string16 markup(UTF8ToUTF16("<div>A \xc3\xb8 \xe6\xb0\xb4</div>")),
236      markup_result;
237  std::string url, url_result;
238
239  {
240    ScopedClipboardWriter clipboard_writer(&clipboard(),
241                                           CLIPBOARD_TYPE_COPY_PASTE);
242    clipboard_writer.WriteHTML(markup, url);
243  }
244
245  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
246                                            CLIPBOARD_TYPE_COPY_PASTE));
247  uint32 fragment_start;
248  uint32 fragment_end;
249  clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, &url_result,
250                       &fragment_start, &fragment_end);
251  EXPECT_PRED2(MarkupMatches, markup, markup_result);
252  EXPECT_EQ(url, url_result);
253  // Make sure that fragment indices were adjusted when converting.
254  EXPECT_EQ(36, fragment_start);
255  EXPECT_EQ(52, fragment_end);
256}
257#endif  // defined(OS_WIN)
258
259// TODO(estade): Port the following test (decide what target we use for urls)
260#if !defined(OS_POSIX) || defined(OS_MACOSX)
261TEST_F(ClipboardTest, BookmarkTest) {
262  base::string16 title(ASCIIToUTF16("The Example Company")), title_result;
263  std::string url("http://www.example.com/"), url_result;
264
265  {
266    ScopedClipboardWriter clipboard_writer(&clipboard(),
267                                           CLIPBOARD_TYPE_COPY_PASTE);
268    clipboard_writer.WriteBookmark(title, url);
269  }
270
271  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetUrlWFormatType(),
272                                            CLIPBOARD_TYPE_COPY_PASTE));
273  clipboard().ReadBookmark(&title_result, &url_result);
274  EXPECT_EQ(title, title_result);
275  EXPECT_EQ(url, url_result);
276}
277#endif  // defined(OS_WIN)
278
279TEST_F(ClipboardTest, MultiFormatTest) {
280  base::string16 text(ASCIIToUTF16("Hi!")), text_result;
281  base::string16 markup(ASCIIToUTF16("<strong>Hi!</string>")), markup_result;
282  std::string url("http://www.example.com/"), url_result;
283  std::string ascii_text;
284
285  {
286    ScopedClipboardWriter clipboard_writer(&clipboard(),
287                                           CLIPBOARD_TYPE_COPY_PASTE);
288    clipboard_writer.WriteHTML(markup, url);
289    clipboard_writer.WriteText(text);
290  }
291
292  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
293                                            CLIPBOARD_TYPE_COPY_PASTE));
294  EXPECT_TRUE(clipboard().IsFormatAvailable(
295      Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
296  EXPECT_TRUE(clipboard().IsFormatAvailable(
297      Clipboard::GetPlainTextFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
298  uint32 ignored;
299  clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &markup_result, &url_result,
300                       &ignored, &ignored);
301  EXPECT_PRED2(MarkupMatches, markup, markup_result);
302#if defined(OS_WIN)
303  // TODO(playmobil): It's not clear that non windows clipboards need to support
304  // this.
305  EXPECT_EQ(url, url_result);
306#endif  // defined(OS_WIN)
307  clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
308  EXPECT_EQ(text, text_result);
309  clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text);
310  EXPECT_EQ(UTF16ToUTF8(text), ascii_text);
311}
312
313TEST_F(ClipboardTest, URLTest) {
314  base::string16 url(ASCIIToUTF16("http://www.google.com/"));
315
316  {
317    ScopedClipboardWriter clipboard_writer(&clipboard(),
318                                           CLIPBOARD_TYPE_COPY_PASTE);
319    clipboard_writer.WriteURL(url);
320  }
321
322  EXPECT_TRUE(clipboard().IsFormatAvailable(
323      Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
324  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetPlainTextFormatType(),
325                                            CLIPBOARD_TYPE_COPY_PASTE));
326  base::string16 text_result;
327  clipboard().ReadText(CLIPBOARD_TYPE_COPY_PASTE, &text_result);
328
329  EXPECT_EQ(text_result, url);
330
331  std::string ascii_text;
332  clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &ascii_text);
333  EXPECT_EQ(UTF16ToUTF8(url), ascii_text);
334
335#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
336  ascii_text.clear();
337  clipboard().ReadAsciiText(CLIPBOARD_TYPE_SELECTION, &ascii_text);
338  EXPECT_EQ(UTF16ToUTF8(url), ascii_text);
339#endif
340}
341
342// TODO(dcheng): The tests for copying to the clipboard also test IPC
343// interaction... consider moving them to a different layer so we can
344// consolidate the validation logic.
345// Note that |bitmap_data| is not premultiplied!
346static void TestBitmapWrite(Clipboard* clipboard,
347                            const uint32* bitmap_data,
348                            size_t bitmap_data_size,
349                            const gfx::Size& size) {
350  // Create shared memory region.
351  base::SharedMemory shared_buf;
352  ASSERT_TRUE(shared_buf.CreateAndMapAnonymous(bitmap_data_size));
353  memcpy(shared_buf.memory(), bitmap_data, bitmap_data_size);
354  // CBF_SMBITMAP expects premultiplied bitmap data so do that now.
355  uint32* pixel_buffer = static_cast<uint32*>(shared_buf.memory());
356  for (int j = 0; j < size.height(); ++j) {
357    for (int i = 0; i < size.width(); ++i) {
358      uint32& pixel = pixel_buffer[i + j * size.width()];
359      pixel = SkPreMultiplyColor(pixel);
360    }
361  }
362  base::SharedMemoryHandle handle_to_share;
363  base::ProcessHandle current_process = base::kNullProcessHandle;
364#if defined(OS_WIN)
365  current_process = GetCurrentProcess();
366#endif
367  shared_buf.ShareToProcess(current_process, &handle_to_share);
368  ASSERT_TRUE(shared_buf.Unmap());
369
370  // Setup data for clipboard().
371  Clipboard::ObjectMapParam placeholder_param;
372  Clipboard::ObjectMapParam size_param;
373  const char* size_data = reinterpret_cast<const char*>(&size);
374  for (size_t i = 0; i < sizeof(size); ++i)
375    size_param.push_back(size_data[i]);
376
377  Clipboard::ObjectMapParams params;
378  params.push_back(placeholder_param);
379  params.push_back(size_param);
380
381  Clipboard::ObjectMap objects;
382  objects[Clipboard::CBF_SMBITMAP] = params;
383  ASSERT_TRUE(Clipboard::ReplaceSharedMemHandle(
384      &objects, handle_to_share, current_process));
385
386  ClipboardTest::WriteObjectsToClipboard(clipboard, objects);
387
388  EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(),
389                                           CLIPBOARD_TYPE_COPY_PASTE));
390  const SkBitmap& image = clipboard->ReadImage(CLIPBOARD_TYPE_COPY_PASTE);
391  EXPECT_EQ(size, gfx::Size(image.width(), image.height()));
392  SkAutoLockPixels image_lock(image);
393  for (int j = 0; j < image.height(); ++j) {
394    const uint32* row_address = image.getAddr32(0, j);
395    for (int i = 0; i < image.width(); ++i) {
396      int offset = i + j * image.width();
397      uint32 pixel = SkPreMultiplyColor(bitmap_data[offset]);
398      EXPECT_EQ(pixel, row_address[i])
399          << "i = " << i << ", j = " << j;
400    }
401  }
402}
403
404TEST_F(ClipboardTest, SharedBitmapTest) {
405  const uint32 fake_bitmap_1[] = {
406    0x46155189, 0xF6A55C8D, 0x79845674, 0xFA57BD89,
407    0x78FD46AE, 0x87C64F5A, 0x36EDC5AF, 0x4378F568,
408    0x91E9F63A, 0xC31EA14F, 0x69AB32DF, 0x643A3FD1,
409  };
410  {
411    SCOPED_TRACE("first bitmap");
412    TestBitmapWrite(
413        &clipboard(), fake_bitmap_1, sizeof(fake_bitmap_1), gfx::Size(4, 3));
414  }
415
416  const uint32 fake_bitmap_2[] = {
417    0x46155189, 0xF6A55C8D,
418    0x79845674, 0xFA57BD89,
419    0x78FD46AE, 0x87C64F5A,
420    0x36EDC5AF, 0x4378F568,
421    0x91E9F63A, 0xC31EA14F,
422    0x69AB32DF, 0x643A3FD1,
423    0xA6DF041D, 0x83046278,
424  };
425  {
426    SCOPED_TRACE("second bitmap");
427    TestBitmapWrite(
428        &clipboard(), fake_bitmap_2, sizeof(fake_bitmap_2), gfx::Size(2, 7));
429  }
430}
431
432namespace {
433// A size class that just happens to have the same layout as gfx::Size!
434struct UnsafeSize {
435  int width;
436  int height;
437};
438COMPILE_ASSERT(sizeof(UnsafeSize) == sizeof(gfx::Size),
439               UnsafeSize_must_be_same_size_as_gfx_Size);
440}  // namespace
441
442TEST_F(ClipboardTest, SharedBitmapWithTwoNegativeSizes) {
443  Clipboard::ObjectMapParam placeholder_param;
444  void* crash_me = reinterpret_cast<void*>(57);
445  placeholder_param.resize(sizeof(crash_me));
446  memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
447
448  Clipboard::ObjectMapParam size_param;
449  UnsafeSize size = {-100, -100};
450  size_param.resize(sizeof(size));
451  memcpy(&size_param.front(), &size, sizeof(size));
452
453  Clipboard::ObjectMapParams params;
454  params.push_back(placeholder_param);
455  params.push_back(size_param);
456
457  Clipboard::ObjectMap objects;
458  objects[Clipboard::CBF_SMBITMAP] = params;
459
460  WriteObjectsToClipboard(objects);
461  EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
462                                             CLIPBOARD_TYPE_COPY_PASTE));
463}
464
465TEST_F(ClipboardTest, SharedBitmapWithOneNegativeSize) {
466  Clipboard::ObjectMapParam placeholder_param;
467  void* crash_me = reinterpret_cast<void*>(57);
468  placeholder_param.resize(sizeof(crash_me));
469  memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
470
471  Clipboard::ObjectMapParam size_param;
472  UnsafeSize size = {-100, 100};
473  size_param.resize(sizeof(size));
474  memcpy(&size_param.front(), &size, sizeof(size));
475
476  Clipboard::ObjectMapParams params;
477  params.push_back(placeholder_param);
478  params.push_back(size_param);
479
480  Clipboard::ObjectMap objects;
481  objects[Clipboard::CBF_SMBITMAP] = params;
482
483  WriteObjectsToClipboard(objects);
484  EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
485                                             CLIPBOARD_TYPE_COPY_PASTE));
486}
487
488TEST_F(ClipboardTest, BitmapWithSuperSize) {
489  Clipboard::ObjectMapParam placeholder_param;
490  void* crash_me = reinterpret_cast<void*>(57);
491  placeholder_param.resize(sizeof(crash_me));
492  memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
493
494  Clipboard::ObjectMapParam size_param;
495  // Width just big enough that bytes per row won't fit in a 32-bit
496  // representation.
497  gfx::Size size(0x20000000, 1);
498  size_param.resize(sizeof(size));
499  memcpy(&size_param.front(), &size, sizeof(size));
500
501  Clipboard::ObjectMapParams params;
502  params.push_back(placeholder_param);
503  params.push_back(size_param);
504
505  Clipboard::ObjectMap objects;
506  objects[Clipboard::CBF_SMBITMAP] = params;
507
508  WriteObjectsToClipboard(objects);
509  EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
510                                             CLIPBOARD_TYPE_COPY_PASTE));
511}
512
513TEST_F(ClipboardTest, BitmapWithSuperSize2) {
514  Clipboard::ObjectMapParam placeholder_param;
515  void* crash_me = reinterpret_cast<void*>(57);
516  placeholder_param.resize(sizeof(crash_me));
517  memcpy(&placeholder_param.front(), &crash_me, sizeof(crash_me));
518
519  Clipboard::ObjectMapParam size_param;
520  // Width and height large enough that SkBitmap::getSize() will be truncated.
521  gfx::Size size(0x0fffffff, 0x0fffffff);
522  size_param.resize(sizeof(size));
523  memcpy(&size_param.front(), &size, sizeof(size));
524
525  Clipboard::ObjectMapParams params;
526  params.push_back(placeholder_param);
527  params.push_back(size_param);
528
529  Clipboard::ObjectMap objects;
530  objects[Clipboard::CBF_SMBITMAP] = params;
531
532  WriteObjectsToClipboard(objects);
533  EXPECT_FALSE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
534                                             CLIPBOARD_TYPE_COPY_PASTE));
535}
536
537TEST_F(ClipboardTest, DataTest) {
538  const ui::Clipboard::FormatType kFormat =
539      ui::Clipboard::GetFormatType("chromium/x-test-format");
540  std::string payload("test string");
541  Pickle write_pickle;
542  write_pickle.WriteString(payload);
543
544  {
545    ScopedClipboardWriter clipboard_writer(&clipboard(),
546                                           CLIPBOARD_TYPE_COPY_PASTE);
547    clipboard_writer.WritePickledData(write_pickle, kFormat);
548  }
549
550  ASSERT_TRUE(clipboard().IsFormatAvailable(
551      kFormat, CLIPBOARD_TYPE_COPY_PASTE));
552  std::string output;
553  clipboard().ReadData(kFormat, &output);
554  ASSERT_FALSE(output.empty());
555
556  Pickle read_pickle(output.data(), output.size());
557  PickleIterator iter(read_pickle);
558  std::string unpickled_string;
559  ASSERT_TRUE(read_pickle.ReadString(&iter, &unpickled_string));
560  EXPECT_EQ(payload, unpickled_string);
561}
562
563TEST_F(ClipboardTest, MultipleDataTest) {
564  const ui::Clipboard::FormatType kFormat1 =
565      ui::Clipboard::GetFormatType("chromium/x-test-format1");
566  std::string payload1("test string1");
567  Pickle write_pickle1;
568  write_pickle1.WriteString(payload1);
569
570  const ui::Clipboard::FormatType kFormat2 =
571      ui::Clipboard::GetFormatType("chromium/x-test-format2");
572  std::string payload2("test string2");
573  Pickle write_pickle2;
574  write_pickle2.WriteString(payload2);
575
576  {
577    ScopedClipboardWriter clipboard_writer(&clipboard(),
578                                           CLIPBOARD_TYPE_COPY_PASTE);
579    clipboard_writer.WritePickledData(write_pickle1, kFormat1);
580    // overwrite the previous pickle for fun
581    clipboard_writer.WritePickledData(write_pickle2, kFormat2);
582  }
583
584  ASSERT_TRUE(clipboard().IsFormatAvailable(
585      kFormat2, CLIPBOARD_TYPE_COPY_PASTE));
586
587  // Check string 2.
588  std::string output2;
589  clipboard().ReadData(kFormat2, &output2);
590  ASSERT_FALSE(output2.empty());
591
592  Pickle read_pickle2(output2.data(), output2.size());
593  PickleIterator iter2(read_pickle2);
594  std::string unpickled_string2;
595  ASSERT_TRUE(read_pickle2.ReadString(&iter2, &unpickled_string2));
596  EXPECT_EQ(payload2, unpickled_string2);
597
598  {
599    ScopedClipboardWriter clipboard_writer(&clipboard(),
600                                           CLIPBOARD_TYPE_COPY_PASTE);
601    clipboard_writer.WritePickledData(write_pickle2, kFormat2);
602    // overwrite the previous pickle for fun
603    clipboard_writer.WritePickledData(write_pickle1, kFormat1);
604  }
605
606  ASSERT_TRUE(clipboard().IsFormatAvailable(
607      kFormat1, CLIPBOARD_TYPE_COPY_PASTE));
608
609  // Check string 1.
610  std::string output1;
611  clipboard().ReadData(kFormat1, &output1);
612  ASSERT_FALSE(output1.empty());
613
614  Pickle read_pickle1(output1.data(), output1.size());
615  PickleIterator iter1(read_pickle1);
616  std::string unpickled_string1;
617  ASSERT_TRUE(read_pickle1.ReadString(&iter1, &unpickled_string1));
618  EXPECT_EQ(payload1, unpickled_string1);
619}
620
621#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
622TEST_F(ClipboardTest, HyperlinkTest) {
623  const std::string kTitle("The <Example> Company's \"home page\"");
624  const std::string kUrl("http://www.example.com?x=3<=3#\"'<>");
625  const std::string kExpectedHtml(
626      "<a href=\"http://www.example.com?x=3&lt=3#&quot;&#39;&lt;&gt;\">"
627      "The &lt;Example&gt; Company&#39;s &quot;home page&quot;</a>");
628
629  std::string url_result;
630  base::string16 html_result;
631  {
632    ScopedClipboardWriter clipboard_writer(&clipboard(),
633                                           CLIPBOARD_TYPE_COPY_PASTE);
634    clipboard_writer.WriteHyperlink(ASCIIToUTF16(kTitle), kUrl);
635  }
636
637  EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetHtmlFormatType(),
638                                            CLIPBOARD_TYPE_COPY_PASTE));
639  uint32 ignored;
640  clipboard().ReadHTML(CLIPBOARD_TYPE_COPY_PASTE, &html_result, &url_result,
641                       &ignored, &ignored);
642  EXPECT_PRED2(MarkupMatches, ASCIIToUTF16(kExpectedHtml), html_result);
643}
644#endif
645
646#if defined(OS_WIN)  // Windows only tests.
647TEST_F(ClipboardTest, WebSmartPasteTest) {
648  {
649    ScopedClipboardWriter clipboard_writer(&clipboard(),
650                                           CLIPBOARD_TYPE_COPY_PASTE);
651    clipboard_writer.WriteWebSmartPaste();
652  }
653
654  EXPECT_TRUE(clipboard().IsFormatAvailable(
655      Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
656}
657
658void HtmlTestHelper(const std::string& cf_html,
659                    const std::string& expected_html) {
660  std::string html;
661  ClipboardUtil::CFHtmlToHtml(cf_html, &html, NULL);
662  EXPECT_EQ(html, expected_html);
663}
664
665TEST_F(ClipboardTest, HtmlTest) {
666  // Test converting from CF_HTML format data with <!--StartFragment--> and
667  // <!--EndFragment--> comments, like from MS Word.
668  HtmlTestHelper("Version:1.0\r\n"
669                 "StartHTML:0000000105\r\n"
670                 "EndHTML:0000000199\r\n"
671                 "StartFragment:0000000123\r\n"
672                 "EndFragment:0000000161\r\n"
673                 "\r\n"
674                 "<html>\r\n"
675                 "<body>\r\n"
676                 "<!--StartFragment-->\r\n"
677                 "\r\n"
678                 "<p>Foo</p>\r\n"
679                 "\r\n"
680                 "<!--EndFragment-->\r\n"
681                 "</body>\r\n"
682                 "</html>\r\n\r\n",
683                 "<p>Foo</p>");
684
685  // Test converting from CF_HTML format data without <!--StartFragment--> and
686  // <!--EndFragment--> comments, like from OpenOffice Writer.
687  HtmlTestHelper("Version:1.0\r\n"
688                 "StartHTML:0000000105\r\n"
689                 "EndHTML:0000000151\r\n"
690                 "StartFragment:0000000121\r\n"
691                 "EndFragment:0000000131\r\n"
692                 "<html>\r\n"
693                 "<body>\r\n"
694                 "<p>Foo</p>\r\n"
695                 "</body>\r\n"
696                 "</html>\r\n\r\n",
697                 "<p>Foo</p>");
698}
699#endif  // defined(OS_WIN)
700
701// Test writing all formats we have simultaneously.
702TEST_F(ClipboardTest, WriteEverything) {
703  {
704    ScopedClipboardWriter writer(&clipboard(), CLIPBOARD_TYPE_COPY_PASTE);
705    writer.WriteText(UTF8ToUTF16("foo"));
706    writer.WriteURL(UTF8ToUTF16("foo"));
707    writer.WriteHTML(UTF8ToUTF16("foo"), "bar");
708    writer.WriteBookmark(UTF8ToUTF16("foo"), "bar");
709    writer.WriteHyperlink(ASCIIToUTF16("foo"), "bar");
710    writer.WriteWebSmartPaste();
711    // Left out: WriteFile, WriteFiles, WriteBitmapFromPixels, WritePickledData.
712  }
713
714  // Passes if we don't crash.
715}
716
717// TODO(dcheng): Fix this test for Android. It's rather involved, since the
718// clipboard change listener is posted to the Java message loop, and spinning
719// that loop from C++ to trigger the callback in the test requires a non-trivial
720// amount of additional work.
721#if !defined(OS_ANDROID)
722// Simple test that the sequence number appears to change when the clipboard is
723// written to.
724// TODO(dcheng): Add a version to test CLIPBOARD_TYPE_SELECTION.
725TEST_F(ClipboardTest, GetSequenceNumber) {
726  const uint64 first_sequence_number =
727      clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE);
728
729  {
730    ScopedClipboardWriter writer(&clipboard(), CLIPBOARD_TYPE_COPY_PASTE);
731    writer.WriteText(UTF8ToUTF16("World"));
732  }
733
734  // On some platforms, the sequence number is updated by a UI callback so pump
735  // the message loop to make sure we get the notification.
736  base::RunLoop().RunUntilIdle();
737
738  const uint64 second_sequence_number =
739      clipboard().GetSequenceNumber(CLIPBOARD_TYPE_COPY_PASTE);
740
741  EXPECT_NE(first_sequence_number, second_sequence_number);
742}
743#endif
744
745#if defined(OS_ANDROID)
746
747// Test that if another application writes some text to the pasteboard the
748// clipboard properly invalidates other types.
749TEST_F(ClipboardTest, InternalClipboardInvalidation) {
750  // Write a Webkit smart paste tag to our clipboard.
751  {
752    ScopedClipboardWriter clipboard_writer(&clipboard(),
753                                           CLIPBOARD_TYPE_COPY_PASTE);
754    clipboard_writer.WriteWebSmartPaste();
755  }
756  EXPECT_TRUE(clipboard().IsFormatAvailable(
757      Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
758
759  //
760  // Simulate that another application copied something in the Clipboard
761  //
762  std::string new_value("Some text copied by some other app");
763  using base::android::ConvertUTF8ToJavaString;
764  using base::android::MethodID;
765  using base::android::ScopedJavaLocalRef;
766
767  JNIEnv* env = base::android::AttachCurrentThread();
768  ASSERT_TRUE(env);
769
770  jobject context = base::android::GetApplicationContext();
771  ASSERT_TRUE(context);
772
773  ScopedJavaLocalRef<jclass> context_class =
774      base::android::GetClass(env, "android/content/Context");
775
776  jmethodID get_system_service = MethodID::Get<MethodID::TYPE_INSTANCE>(
777      env, context_class.obj(), "getSystemService",
778      "(Ljava/lang/String;)Ljava/lang/Object;");
779
780  // Retrieve the system service.
781  ScopedJavaLocalRef<jstring> service_name = ConvertUTF8ToJavaString(
782      env, "clipboard");
783  ScopedJavaLocalRef<jobject> clipboard_manager(
784      env, env->CallObjectMethod(
785        context, get_system_service, service_name.obj()));
786  ASSERT_TRUE(clipboard_manager.obj() && !base::android::ClearException(env));
787
788  ScopedJavaLocalRef<jclass> clipboard_class =
789      base::android::GetClass(env, "android/text/ClipboardManager");
790  jmethodID set_text = MethodID::Get<MethodID::TYPE_INSTANCE>(
791      env, clipboard_class.obj(), "setText", "(Ljava/lang/CharSequence;)V");
792  ScopedJavaLocalRef<jstring> new_value_string = ConvertUTF8ToJavaString(
793      env, new_value.c_str());
794
795  // Will need to call toString as CharSequence is not always a String.
796  env->CallVoidMethod(clipboard_manager.obj(),
797                      set_text,
798                      new_value_string.obj());
799
800  // The WebKit smart paste tag should now be gone.
801  EXPECT_FALSE(clipboard().IsFormatAvailable(
802      Clipboard::GetWebKitSmartPasteFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
803
804  // Make sure some text is available
805  EXPECT_TRUE(clipboard().IsFormatAvailable(
806      Clipboard::GetPlainTextWFormatType(), CLIPBOARD_TYPE_COPY_PASTE));
807
808  // Make sure the text is what we inserted while simulating the other app
809  std::string contents;
810  clipboard().ReadAsciiText(CLIPBOARD_TYPE_COPY_PASTE, &contents);
811  EXPECT_EQ(contents, new_value);
812}
813#endif
814}  // namespace ui
815