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 "ppapi/tests/test_flash_clipboard.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "ppapi/cpp/instance.h"
11#include "ppapi/cpp/module.h"
12#include "ppapi/cpp/point.h"
13#include "ppapi/cpp/private/flash_clipboard.h"
14#include "ppapi/cpp/var.h"
15#include "ppapi/cpp/var_array_buffer.h"
16#include "ppapi/tests/testing_instance.h"
17
18// http://crbug.com/176822
19#if !defined(OS_WIN)
20REGISTER_TEST_CASE(FlashClipboard);
21#endif
22
23// WriteData() sends an async request to the browser process. As a result, the
24// string written may not be reflected by IsFormatAvailable() or ReadPlainText()
25// immediately. We need to wait and retry.
26const int kIntervalMs = 250;
27const int kMaxIntervals = kActionTimeoutMs / kIntervalMs;
28
29TestFlashClipboard::TestFlashClipboard(TestingInstance* instance)
30    : TestCase(instance) {
31}
32
33void TestFlashClipboard::RunTests(const std::string& filter) {
34  RUN_TEST(ReadWritePlainText, filter);
35  RUN_TEST(ReadWriteHTML, filter);
36  RUN_TEST(ReadWriteRTF, filter);
37  RUN_TEST(ReadWriteCustomData, filter);
38  RUN_TEST(ReadWriteMultipleFormats, filter);
39  RUN_TEST(Clear, filter);
40  RUN_TEST(InvalidFormat, filter);
41  RUN_TEST(RegisterCustomFormat, filter);
42}
43
44bool TestFlashClipboard::ReadStringVar(uint32_t format, std::string* result) {
45  pp::Var text;
46  bool success = pp::flash::Clipboard::ReadData(
47      instance_,
48      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
49      format,
50      &text);
51  if (success && text.is_string()) {
52    *result = text.AsString();
53    return true;
54  }
55  return false;
56}
57
58bool TestFlashClipboard::WriteStringVar(uint32_t format,
59                                        const std::string& text) {
60  std::vector<uint32_t> formats_vector(1, format);
61  std::vector<pp::Var> data_vector(1, pp::Var(text));
62  bool success = pp::flash::Clipboard::WriteData(
63      instance_,
64      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
65      formats_vector,
66      data_vector);
67  return success;
68}
69
70bool TestFlashClipboard::IsFormatAvailableMatches(uint32_t format,
71                                                  bool expected) {
72  for (int i = 0; i < kMaxIntervals; ++i) {
73    bool is_available = pp::flash::Clipboard::IsFormatAvailable(
74        instance_,
75        PP_FLASH_CLIPBOARD_TYPE_STANDARD,
76        format);
77    if (is_available == expected)
78      return true;
79
80    PlatformSleep(kIntervalMs);
81  }
82  return false;
83}
84
85bool TestFlashClipboard::ReadPlainTextMatches(const std::string& expected) {
86  for (int i = 0; i < kMaxIntervals; ++i) {
87    std::string result;
88    bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, &result);
89    if (success && result == expected)
90      return true;
91
92    PlatformSleep(kIntervalMs);
93  }
94  return false;
95}
96
97bool TestFlashClipboard::ReadHTMLMatches(const std::string& expected) {
98  for (int i = 0; i < kMaxIntervals; ++i) {
99    std::string result;
100    bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, &result);
101    // Harmless markup may be inserted around the copied html on some
102    // platforms, so just check that the pasted string contains the
103    // copied string. Also check that we only paste the copied fragment, see
104    // http://code.google.com/p/chromium/issues/detail?id=130827.
105    if (success && result.find(expected) != std::string::npos &&
106        result.find("<!--StartFragment-->") == std::string::npos &&
107        result.find("<!--EndFragment-->") == std::string::npos) {
108      return true;
109    }
110
111    PlatformSleep(kIntervalMs);
112  }
113  return false;
114}
115
116std::string TestFlashClipboard::TestReadWritePlainText() {
117  std::string input = "Hello world plain text!";
118  ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input));
119  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT,
120                                       true));
121  ASSERT_TRUE(ReadPlainTextMatches(input));
122
123  PASS();
124}
125
126std::string TestFlashClipboard::TestReadWriteHTML() {
127  std::string input = "Hello world html!";
128  ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, input));
129  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true));
130  ASSERT_TRUE(ReadHTMLMatches(input));
131
132  PASS();
133}
134
135std::string TestFlashClipboard::TestReadWriteRTF() {
136  std::string rtf_string =
137        "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\n"
138        "This is some {\\b bold} text.\\par\n"
139        "}";
140  pp::VarArrayBuffer array_buffer(rtf_string.size());
141  char* bytes = static_cast<char*>(array_buffer.Map());
142  std::copy(rtf_string.data(), rtf_string.data() + rtf_string.size(), bytes);
143  std::vector<uint32_t> formats_vector(1, PP_FLASH_CLIPBOARD_FORMAT_RTF);
144  std::vector<pp::Var> data_vector(1, array_buffer);
145  ASSERT_TRUE(pp::flash::Clipboard::WriteData(
146      instance_,
147      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
148      formats_vector,
149      data_vector));
150
151  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_RTF, true));
152
153  pp::Var rtf_result;
154  ASSERT_TRUE(pp::flash::Clipboard::ReadData(
155        instance_,
156        PP_FLASH_CLIPBOARD_TYPE_STANDARD,
157        PP_FLASH_CLIPBOARD_FORMAT_RTF,
158        &rtf_result));
159  ASSERT_TRUE(rtf_result.is_array_buffer());
160  pp::VarArrayBuffer array_buffer_result(rtf_result);
161  ASSERT_TRUE(array_buffer_result.ByteLength() == array_buffer.ByteLength());
162  char* bytes_result = static_cast<char*>(array_buffer_result.Map());
163  ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(),
164      bytes_result));
165
166  PASS();
167}
168
169std::string TestFlashClipboard::TestReadWriteCustomData() {
170  std::string custom_data = "custom_data";
171  pp::VarArrayBuffer array_buffer(custom_data.size());
172  char* bytes = static_cast<char*>(array_buffer.Map());
173  std::copy(custom_data.begin(), custom_data.end(), bytes);
174  uint32_t format_id =
175      pp::flash::Clipboard::RegisterCustomFormat(instance_, "my-format");
176  ASSERT_NE(format_id, PP_FLASH_CLIPBOARD_FORMAT_INVALID);
177
178  std::vector<uint32_t> formats_vector(1, format_id);
179  std::vector<pp::Var> data_vector(1, array_buffer);
180  ASSERT_TRUE(pp::flash::Clipboard::WriteData(
181      instance_,
182      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
183      formats_vector,
184      data_vector));
185
186  ASSERT_TRUE(IsFormatAvailableMatches(format_id, true));
187
188  pp::Var custom_data_result;
189  ASSERT_TRUE(pp::flash::Clipboard::ReadData(
190      instance_,
191      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
192      format_id,
193      &custom_data_result));
194  ASSERT_TRUE(custom_data_result.is_array_buffer());
195  pp::VarArrayBuffer array_buffer_result(custom_data_result);
196  ASSERT_EQ(array_buffer_result.ByteLength(), array_buffer.ByteLength());
197  char* bytes_result = static_cast<char*>(array_buffer_result.Map());
198  ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(),
199      bytes_result));
200
201  PASS();
202}
203
204std::string TestFlashClipboard::TestReadWriteMultipleFormats() {
205  std::vector<uint32_t> formats;
206  std::vector<pp::Var> data;
207  formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT);
208  data.push_back(pp::Var("plain text"));
209  formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_HTML);
210  data.push_back(pp::Var("html"));
211  bool success = pp::flash::Clipboard::WriteData(
212      instance_,
213      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
214      formats,
215      data);
216  ASSERT_TRUE(success);
217  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT,
218                                       true));
219  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true));
220  ASSERT_TRUE(ReadPlainTextMatches(data[0].AsString()));
221  ASSERT_TRUE(ReadHTMLMatches(data[1].AsString()));
222
223  PASS();
224}
225
226std::string TestFlashClipboard::TestClear() {
227  std::string input = "Hello world plain text!";
228  ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input));
229  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT,
230                                       true));
231  bool success = pp::flash::Clipboard::WriteData(
232      instance_,
233      PP_FLASH_CLIPBOARD_TYPE_STANDARD,
234      std::vector<uint32_t>(),
235      std::vector<pp::Var>());
236  ASSERT_TRUE(success);
237  ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT,
238                                       false));
239
240  PASS();
241}
242
243std::string TestFlashClipboard::TestInvalidFormat() {
244  uint32_t invalid_format = 999;
245  ASSERT_FALSE(WriteStringVar(invalid_format, "text"));
246  ASSERT_TRUE(IsFormatAvailableMatches(invalid_format, false));
247  std::string unused;
248  ASSERT_FALSE(ReadStringVar(invalid_format, &unused));
249
250  PASS();
251}
252
253std::string TestFlashClipboard::TestRegisterCustomFormat() {
254  // Test an empty name is rejected.
255  uint32_t format_id =
256      pp::flash::Clipboard::RegisterCustomFormat(instance_, std::string());
257  ASSERT_EQ(format_id, PP_FLASH_CLIPBOARD_FORMAT_INVALID);
258
259  // Test a valid format name.
260  format_id = pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b");
261  ASSERT_NE(format_id, PP_FLASH_CLIPBOARD_FORMAT_INVALID);
262  // Make sure the format doesn't collide with predefined formats.
263  ASSERT_NE(format_id, PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT);
264  ASSERT_NE(format_id, PP_FLASH_CLIPBOARD_FORMAT_HTML);
265  ASSERT_NE(format_id, PP_FLASH_CLIPBOARD_FORMAT_RTF);
266
267  // Check that if the same name is registered, the same id comes out.
268  uint32_t format_id2 =
269      pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b");
270  ASSERT_EQ(format_id, format_id2);
271
272  // Check that the second format registered has a different id.
273  uint32_t format_id3 =
274      pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b-c");
275  ASSERT_NE(format_id, format_id3);
276
277  PASS();
278}
279