| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ppapi/tests/test_flash_clipboard.h" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "ppapi/cpp/instance.h" |
| #include "ppapi/cpp/module.h" |
| #include "ppapi/cpp/point.h" |
| #include "ppapi/cpp/private/flash_clipboard.h" |
| #include "ppapi/cpp/var.h" |
| #include "ppapi/cpp/var_array_buffer.h" |
| #include "ppapi/tests/testing_instance.h" |
| |
| // http://crbug.com/176822 |
| #if !defined(OS_WIN) |
| REGISTER_TEST_CASE(FlashClipboard); |
| #endif |
| |
| // WriteData() sends an async request to the browser process. As a result, the |
| // string written may not be reflected by IsFormatAvailable() or ReadPlainText() |
| // immediately. We need to wait and retry. |
| const int kIntervalMs = 250; |
| const int kMaxIntervals = kActionTimeoutMs / kIntervalMs; |
| |
| TestFlashClipboard::TestFlashClipboard(TestingInstance* instance) |
| : TestCase(instance) { |
| } |
| |
| void TestFlashClipboard::RunTests(const std::string& filter) { |
| RUN_TEST(ReadWritePlainText, filter); |
| RUN_TEST(ReadWriteHTML, filter); |
| RUN_TEST(ReadWriteRTF, filter); |
| RUN_TEST(ReadWriteCustomData, filter); |
| RUN_TEST(ReadWriteMultipleFormats, filter); |
| RUN_TEST(Clear, filter); |
| RUN_TEST(InvalidFormat, filter); |
| RUN_TEST(RegisterCustomFormat, filter); |
| RUN_TEST(GetSequenceNumber, filter); |
| } |
| |
| bool TestFlashClipboard::ReadStringVar(uint32_t format, std::string* result) { |
| pp::Var text; |
| bool success = pp::flash::Clipboard::ReadData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| format, |
| &text); |
| if (success && text.is_string()) { |
| *result = text.AsString(); |
| return true; |
| } |
| return false; |
| } |
| |
| bool TestFlashClipboard::WriteStringVar(uint32_t format, |
| const std::string& text) { |
| std::vector<uint32_t> formats_vector(1, format); |
| std::vector<pp::Var> data_vector(1, pp::Var(text)); |
| bool success = pp::flash::Clipboard::WriteData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| formats_vector, |
| data_vector); |
| return success; |
| } |
| |
| bool TestFlashClipboard::IsFormatAvailableMatches(uint32_t format, |
| bool expected) { |
| for (int i = 0; i < kMaxIntervals; ++i) { |
| bool is_available = pp::flash::Clipboard::IsFormatAvailable( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| format); |
| if (is_available == expected) |
| return true; |
| |
| PlatformSleep(kIntervalMs); |
| } |
| return false; |
| } |
| |
| bool TestFlashClipboard::ReadPlainTextMatches(const std::string& expected) { |
| for (int i = 0; i < kMaxIntervals; ++i) { |
| std::string result; |
| bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, &result); |
| if (success && result == expected) |
| return true; |
| |
| PlatformSleep(kIntervalMs); |
| } |
| return false; |
| } |
| |
| bool TestFlashClipboard::ReadHTMLMatches(const std::string& expected) { |
| for (int i = 0; i < kMaxIntervals; ++i) { |
| std::string result; |
| bool success = ReadStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, &result); |
| // Harmless markup may be inserted around the copied html on some |
| // platforms, so just check that the pasted string contains the |
| // copied string. Also check that we only paste the copied fragment, see |
| // http://code.google.com/p/chromium/issues/detail?id=130827. |
| if (success && result.find(expected) != std::string::npos && |
| result.find("<!--StartFragment-->") == std::string::npos && |
| result.find("<!--EndFragment-->") == std::string::npos) { |
| return true; |
| } |
| |
| PlatformSleep(kIntervalMs); |
| } |
| return false; |
| } |
| |
| uint64_t TestFlashClipboard::GetSequenceNumber(uint64_t last_sequence_number) { |
| uint64_t next_sequence_number = last_sequence_number; |
| for (int i = 0; i < kMaxIntervals; ++i) { |
| pp::flash::Clipboard::GetSequenceNumber( |
| instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &next_sequence_number); |
| if (next_sequence_number != last_sequence_number) |
| return next_sequence_number; |
| |
| PlatformSleep(kIntervalMs); |
| } |
| return next_sequence_number; |
| } |
| |
| std::string TestFlashClipboard::TestReadWritePlainText() { |
| std::string input = "Hello world plain text!"; |
| ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input)); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, |
| true)); |
| ASSERT_TRUE(ReadPlainTextMatches(input)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestReadWriteHTML() { |
| std::string input = "Hello world html!"; |
| ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, input)); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true)); |
| ASSERT_TRUE(ReadHTMLMatches(input)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestReadWriteRTF() { |
| std::string rtf_string = |
| "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\n" |
| "This is some {\\b bold} text.\\par\n" |
| "}"; |
| pp::VarArrayBuffer array_buffer(static_cast<uint32_t>(rtf_string.size())); |
| char* bytes = static_cast<char*>(array_buffer.Map()); |
| std::copy(rtf_string.data(), rtf_string.data() + rtf_string.size(), bytes); |
| std::vector<uint32_t> formats_vector(1, PP_FLASH_CLIPBOARD_FORMAT_RTF); |
| std::vector<pp::Var> data_vector(1, array_buffer); |
| ASSERT_TRUE(pp::flash::Clipboard::WriteData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| formats_vector, |
| data_vector)); |
| |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_RTF, true)); |
| |
| pp::Var rtf_result; |
| ASSERT_TRUE(pp::flash::Clipboard::ReadData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| PP_FLASH_CLIPBOARD_FORMAT_RTF, |
| &rtf_result)); |
| ASSERT_TRUE(rtf_result.is_array_buffer()); |
| pp::VarArrayBuffer array_buffer_result(rtf_result); |
| ASSERT_TRUE(array_buffer_result.ByteLength() == array_buffer.ByteLength()); |
| char* bytes_result = static_cast<char*>(array_buffer_result.Map()); |
| ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(), |
| bytes_result)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestReadWriteCustomData() { |
| std::string custom_data = "custom_data"; |
| pp::VarArrayBuffer array_buffer(static_cast<uint32_t>(custom_data.size())); |
| char* bytes = static_cast<char*>(array_buffer.Map()); |
| std::copy(custom_data.begin(), custom_data.end(), bytes); |
| uint32_t format_id = |
| pp::flash::Clipboard::RegisterCustomFormat(instance_, "my-format"); |
| ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), |
| format_id); |
| |
| std::vector<uint32_t> formats_vector(1, format_id); |
| std::vector<pp::Var> data_vector(1, array_buffer); |
| ASSERT_TRUE(pp::flash::Clipboard::WriteData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| formats_vector, |
| data_vector)); |
| |
| ASSERT_TRUE(IsFormatAvailableMatches(format_id, true)); |
| |
| pp::Var custom_data_result; |
| ASSERT_TRUE(pp::flash::Clipboard::ReadData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| format_id, |
| &custom_data_result)); |
| ASSERT_TRUE(custom_data_result.is_array_buffer()); |
| pp::VarArrayBuffer array_buffer_result(custom_data_result); |
| ASSERT_EQ(array_buffer_result.ByteLength(), array_buffer.ByteLength()); |
| char* bytes_result = static_cast<char*>(array_buffer_result.Map()); |
| ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(), |
| bytes_result)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestReadWriteMultipleFormats() { |
| std::vector<uint32_t> formats; |
| std::vector<pp::Var> data; |
| formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT); |
| data.push_back(pp::Var("plain text")); |
| formats.push_back(PP_FLASH_CLIPBOARD_FORMAT_HTML); |
| data.push_back(pp::Var("html")); |
| bool success = pp::flash::Clipboard::WriteData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| formats, |
| data); |
| ASSERT_TRUE(success); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, |
| true)); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_HTML, true)); |
| ASSERT_TRUE(ReadPlainTextMatches(data[0].AsString())); |
| ASSERT_TRUE(ReadHTMLMatches(data[1].AsString())); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestClear() { |
| std::string input = "Hello world plain text!"; |
| ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, input)); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, |
| true)); |
| bool success = pp::flash::Clipboard::WriteData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| std::vector<uint32_t>(), |
| std::vector<pp::Var>()); |
| ASSERT_TRUE(success); |
| ASSERT_TRUE(IsFormatAvailableMatches(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT, |
| false)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestInvalidFormat() { |
| uint32_t invalid_format = 999; |
| ASSERT_FALSE(WriteStringVar(invalid_format, "text")); |
| ASSERT_TRUE(IsFormatAvailableMatches(invalid_format, false)); |
| std::string unused; |
| ASSERT_FALSE(ReadStringVar(invalid_format, &unused)); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestRegisterCustomFormat() { |
| // Test an empty name is rejected. |
| uint32_t format_id = |
| pp::flash::Clipboard::RegisterCustomFormat(instance_, std::string()); |
| ASSERT_EQ(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), |
| format_id); |
| |
| // Test a valid format name. |
| format_id = pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b"); |
| ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_INVALID), |
| format_id); |
| // Make sure the format doesn't collide with predefined formats. |
| ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT), |
| format_id); |
| ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_HTML), |
| format_id); |
| ASSERT_NE(static_cast<uint32_t>(PP_FLASH_CLIPBOARD_FORMAT_RTF), |
| format_id); |
| |
| // Check that if the same name is registered, the same id comes out. |
| uint32_t format_id2 = |
| pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b"); |
| ASSERT_EQ(format_id, format_id2); |
| |
| // Check that the second format registered has a different id. |
| uint32_t format_id3 = |
| pp::flash::Clipboard::RegisterCustomFormat(instance_, "a-b-c"); |
| ASSERT_NE(format_id, format_id3); |
| |
| PASS(); |
| } |
| |
| std::string TestFlashClipboard::TestGetSequenceNumber() { |
| uint64_t sequence_number_before = 0; |
| uint64_t sequence_number_after = 0; |
| ASSERT_TRUE(pp::flash::Clipboard::GetSequenceNumber( |
| instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &sequence_number_before)); |
| |
| // Test the sequence number changes after writing html. |
| ASSERT_TRUE(WriteStringVar(PP_FLASH_CLIPBOARD_FORMAT_HTML, "<html>")); |
| sequence_number_after = GetSequenceNumber(sequence_number_before); |
| ASSERT_NE(sequence_number_before, sequence_number_after); |
| sequence_number_before = sequence_number_after; |
| |
| // Test the sequence number changes after writing some custom data. |
| std::string custom_data = "custom_data"; |
| pp::VarArrayBuffer array_buffer(static_cast<uint32_t>(custom_data.size())); |
| char* bytes = static_cast<char*>(array_buffer.Map()); |
| std::copy(custom_data.begin(), custom_data.end(), bytes); |
| uint32_t format_id = |
| pp::flash::Clipboard::RegisterCustomFormat(instance_, "my-format"); |
| std::vector<uint32_t> formats_vector(1, format_id); |
| std::vector<pp::Var> data_vector(1, array_buffer); |
| ASSERT_TRUE(pp::flash::Clipboard::WriteData(instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| formats_vector, |
| data_vector)); |
| sequence_number_after = GetSequenceNumber(sequence_number_before); |
| ASSERT_NE(sequence_number_before, sequence_number_after); |
| sequence_number_before = sequence_number_after; |
| |
| // Read the data and make sure the sequence number doesn't change. |
| pp::Var custom_data_result; |
| ASSERT_TRUE(pp::flash::Clipboard::ReadData( |
| instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| format_id, |
| &custom_data_result)); |
| ASSERT_TRUE(pp::flash::Clipboard::GetSequenceNumber( |
| instance_, PP_FLASH_CLIPBOARD_TYPE_STANDARD, &sequence_number_after)); |
| ASSERT_EQ(sequence_number_before, sequence_number_after); |
| sequence_number_before = sequence_number_after; |
| |
| // Clear the clipboard and check the sequence number changes. |
| pp::flash::Clipboard::WriteData(instance_, |
| PP_FLASH_CLIPBOARD_TYPE_STANDARD, |
| std::vector<uint32_t>(), |
| std::vector<pp::Var>()); |
| sequence_number_after = GetSequenceNumber(sequence_number_before); |
| ASSERT_NE(sequence_number_before, sequence_number_after); |
| |
| PASS(); |
| } |