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) 20 REGISTER_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. 26 const int kIntervalMs = 250; 27 const int kMaxIntervals = kActionTimeoutMs / kIntervalMs; 28 29 TestFlashClipboard::TestFlashClipboard(TestingInstance* instance) 30 : TestCase(instance) { 31 } 32 33 void 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 RUN_TEST(GetSequenceNumber, filter); 43 } 44 45 bool TestFlashClipboard::ReadStringVar(uint32_t format, std::string* result) { 46 pp::Var text; 47 bool success = pp::flash::Clipboard::ReadData( 48 instance_, 49 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 50 format, 51 &text); 52 if (success && text.is_string()) { 53 *result = text.AsString(); 54 return true; 55 } 56 return false; 57 } 58 59 bool TestFlashClipboard::WriteStringVar(uint32_t format, 60 const std::string& text) { 61 std::vector<uint32_t> formats_vector(1, format); 62 std::vector<pp::Var> data_vector(1, pp::Var(text)); 63 bool success = pp::flash::Clipboard::WriteData( 64 instance_, 65 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 66 formats_vector, 67 data_vector); 68 return success; 69 } 70 71 bool TestFlashClipboard::IsFormatAvailableMatches(uint32_t format, 72 bool expected) { 73 for (int i = 0; i < kMaxIntervals; ++i) { 74 bool is_available = pp::flash::Clipboard::IsFormatAvailable( 75 instance_, 76 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 77 format); 78 if (is_available == expected) 79 return true; 80 81 PlatformSleep(kIntervalMs); 82 } 83 return false; 84 } 85 86 bool TestFlashClipboard::ReadPlainTextMatches(const std::string& expected) { 87 for (int i = 0; i < kMaxIntervals; ++i) { 88 std::string result; 89 bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, &result); 90 if (success && result == expected) 91 return true; 92 93 PlatformSleep(kIntervalMs); 94 } 95 return false; 96 } 97 98 bool TestFlashClipboard::ReadHTMLMatches(const std::string& expected) { 99 for (int i = 0; i < kMaxIntervals; ++i) { 100 std::string result; 101 bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, &result); 102 // Harmless markup may be inserted around the copied html on some 103 // platforms, so just check that the pasted string contains the 104 // copied string. Also check that we only paste the copied fragment, see 105 // http://code.google.com/p/chromium/issues/detail?id=130827. 106 if (success && result.find(expected) != std::string::npos && 107 result.find("<!--StartFragment-->") == std::string::npos && 108 result.find("<!--EndFragment-->") == std::string::npos) { 109 return true; 110 } 111 112 PlatformSleep(kIntervalMs); 113 } 114 return false; 115 } 116 117 uint64_t TestFlashClipboard::GetSequenceNumber(uint64_t last_sequence_number) { 118 uint64_t next_sequence_number = last_sequence_number; 119 for (int i = 0; i < kMaxIntervals; ++i) { 120 pp::flash::Clipboard::GetSequenceNumber( 121 instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &next_sequence_number); 122 if (next_sequence_number != last_sequence_number) 123 return next_sequence_number; 124 125 PlatformSleep(kIntervalMs); 126 } 127 return next_sequence_number; 128 } 129 130 std::string TestFlashClipboard::TestReadWritePlainText() { 131 std::string input = "Hello world plain text!"; 132 ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input)); 133 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, 134 true)); 135 ASSERT_TRUE(ReadPlainTextMatches(input)); 136 137 PASS(); 138 } 139 140 std::string TestFlashClipboard::TestReadWriteHTML() { 141 std::string input = "Hello world html!"; 142 ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, input)); 143 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true)); 144 ASSERT_TRUE(ReadHTMLMatches(input)); 145 146 PASS(); 147 } 148 149 std::string TestFlashClipboard::TestReadWriteRTF() { 150 std::string rtf_string = 151 "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\n" 152 "This is some {\\b bold} text.\\par\n" 153 "}"; 154 pp::VarArrayBuffer array_buffer(rtf_string.size()); 155 char* bytes = static_cast<char*>(array_buffer.Map()); 156 std::copy(rtf_string.data(), rtf_string.data() + rtf_string.size(), bytes); 157 std::vector<uint32_t> formats_vector(1, PP_FLASH_CLIPBOARD_FORMAT_RTF); 158 std::vector<pp::Var> data_vector(1, array_buffer); 159 ASSERT_TRUE(pp::flash::Clipboard::WriteData( 160 instance_, 161 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 162 formats_vector, 163 data_vector)); 164 165 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_RTF, true)); 166 167 pp::Var rtf_result; 168 ASSERT_TRUE(pp::flash::Clipboard::ReadData( 169 instance_, 170 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 171 PP_FLASH_CLIPBOARD_FORMAT_RTF, 172 &rtf_result)); 173 ASSERT_TRUE(rtf_result.is_array_buffer()); 174 pp::VarArrayBuffer array_buffer_result(rtf_result); 175 ASSERT_TRUE(array_buffer_result.ByteLength() == array_buffer.ByteLength()); 176 char* bytes_result = static_cast<char*>(array_buffer_result.Map()); 177 ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(), 178 bytes_result)); 179 180 PASS(); 181 } 182 183 std::string TestFlashClipboard::TestReadWriteCustomData() { 184 std::string custom_data = "custom_data"; 185 pp::VarArrayBuffer array_buffer(custom_data.size()); 186 char* bytes = static_cast<char*>(array_buffer.Map()); 187 std::copy(custom_data.begin(), custom_data.end(), bytes); 188 uint32_t format_id = 189 pp::flash::Clipboard::RegisterCustomFormat(instance_, "my-format"); 190 ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), 191 format_id); 192 193 std::vector<uint32_t> formats_vector(1, format_id); 194 std::vector<pp::Var> data_vector(1, array_buffer); 195 ASSERT_TRUE(pp::flash::Clipboard::WriteData( 196 instance_, 197 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 198 formats_vector, 199 data_vector)); 200 201 ASSERT_TRUE(IsFormatAvailableMatches(format_id, true)); 202 203 pp::Var custom_data_result; 204 ASSERT_TRUE(pp::flash::Clipboard::ReadData( 205 instance_, 206 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 207 format_id, 208 &custom_data_result)); 209 ASSERT_TRUE(custom_data_result.is_array_buffer()); 210 pp::VarArrayBuffer array_buffer_result(custom_data_result); 211 ASSERT_EQ(array_buffer_result.ByteLength(), array_buffer.ByteLength()); 212 char* bytes_result = static_cast<char*>(array_buffer_result.Map()); 213 ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(), 214 bytes_result)); 215 216 PASS(); 217 } 218 219 std::string TestFlashClipboard::TestReadWriteMultipleFormats() { 220 std::vector<uint32_t> formats; 221 std::vector<pp::Var> data; 222 formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT); 223 data.push_back(pp::Var("plain text")); 224 formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_HTML); 225 data.push_back(pp::Var("html")); 226 bool success = pp::flash::Clipboard::WriteData( 227 instance_, 228 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 229 formats, 230 data); 231 ASSERT_TRUE(success); 232 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, 233 true)); 234 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true)); 235 ASSERT_TRUE(ReadPlainTextMatches(data[0].AsString())); 236 ASSERT_TRUE(ReadHTMLMatches(data[1].AsString())); 237 238 PASS(); 239 } 240 241 std::string TestFlashClipboard::TestClear() { 242 std::string input = "Hello world plain text!"; 243 ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input)); 244 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, 245 true)); 246 bool success = pp::flash::Clipboard::WriteData( 247 instance_, 248 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 249 std::vector<uint32_t>(), 250 std::vector<pp::Var>()); 251 ASSERT_TRUE(success); 252 ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, 253 false)); 254 255 PASS(); 256 } 257 258 std::string TestFlashClipboard::TestInvalidFormat() { 259 uint32_t invalid_format = 999; 260 ASSERT_FALSE(WriteStringVar(invalid_format, "text")); 261 ASSERT_TRUE(IsFormatAvailableMatches(invalid_format, false)); 262 std::string unused; 263 ASSERT_FALSE(ReadStringVar(invalid_format, &unused)); 264 265 PASS(); 266 } 267 268 std::string TestFlashClipboard::TestRegisterCustomFormat() { 269 // Test an empty name is rejected. 270 uint32_t format_id = 271 pp::flash::Clipboard::RegisterCustomFormat(instance_, std::string()); 272 ASSERT_EQ(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), 273 format_id); 274 275 // Test a valid format name. 276 format_id = pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b"); 277 ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), 278 format_id); 279 // Make sure the format doesn't collide with predefined formats. 280 ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT), 281 format_id); 282 ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_HTML), 283 format_id); 284 ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_RTF), 285 format_id); 286 287 // Check that if the same name is registered, the same id comes out. 288 uint32_t format_id2 = 289 pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b"); 290 ASSERT_EQ(format_id, format_id2); 291 292 // Check that the second format registered has a different id. 293 uint32_t format_id3 = 294 pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b-c"); 295 ASSERT_NE(format_id, format_id3); 296 297 PASS(); 298 } 299 300 std::string TestFlashClipboard::TestGetSequenceNumber() { 301 uint64_t sequence_number_before = 0; 302 uint64_t sequence_number_after = 0; 303 ASSERT_TRUE(pp::flash::Clipboard::GetSequenceNumber( 304 instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &sequence_number_before)); 305 306 // Test the sequence number changes after writing html. 307 ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, "<html>")); 308 sequence_number_after = GetSequenceNumber(sequence_number_before); 309 ASSERT_NE(sequence_number_before, sequence_number_after); 310 sequence_number_before = sequence_number_after; 311 312 // Test the sequence number changes after writing some custom data. 313 std::string custom_data = "custom_data"; 314 pp::VarArrayBuffer array_buffer(custom_data.size()); 315 char* bytes = static_cast<char*>(array_buffer.Map()); 316 std::copy(custom_data.begin(), custom_data.end(), bytes); 317 uint32_t format_id = 318 pp::flash::Clipboard::RegisterCustomFormat(instance_, "my-format"); 319 std::vector<uint32_t> formats_vector(1, format_id); 320 std::vector<pp::Var> data_vector(1, array_buffer); 321 ASSERT_TRUE(pp::flash::Clipboard::WriteData(instance_, 322 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 323 formats_vector, 324 data_vector)); 325 sequence_number_after = GetSequenceNumber(sequence_number_before); 326 ASSERT_NE(sequence_number_before, sequence_number_after); 327 sequence_number_before = sequence_number_after; 328 329 // Read the data and make sure the sequence number doesn't change. 330 pp::Var custom_data_result; 331 ASSERT_TRUE(pp::flash::Clipboard::ReadData( 332 instance_, 333 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 334 format_id, 335 &custom_data_result)); 336 ASSERT_TRUE(pp::flash::Clipboard::GetSequenceNumber( 337 instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &sequence_number_after)); 338 ASSERT_EQ(sequence_number_before, sequence_number_after); 339 sequence_number_before = sequence_number_after; 340 341 // Clear the clipboard and check the sequence number changes. 342 pp::flash::Clipboard::WriteData(instance_, 343 PP_FLASH_CLIPBOARD_TYPE_STANDARD, 344 std::vector<uint32_t>(), 345 std::vector<pp::Var>()); 346 sequence_number_after = GetSequenceNumber(sequence_number_before); 347 ASSERT_NE(sequence_number_before, sequence_number_after); 348 349 PASS(); 350 } 351