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