// 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 #include #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 formats_vector(1, format); std::vector 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("") == std::string::npos && result.find("") == 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(rtf_string.size())); char* bytes = static_cast(array_buffer.Map()); std::copy(rtf_string.data(), rtf_string.data() + rtf_string.size(), bytes); std::vector formats_vector(1, PP_FLASH_CLIPBOARD_FORMAT_RTF); std::vector 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(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(custom_data.size())); char* bytes = static_cast(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(PP_FLASH_CLIPBOARD_FORMAT_INVALID), format_id); std::vector formats_vector(1, format_id); std::vector 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(array_buffer_result.Map()); ASSERT_TRUE(std::equal(bytes, bytes + array_buffer.ByteLength(), bytes_result)); PASS(); } std::string TestFlashClipboard::TestReadWriteMultipleFormats() { std::vector formats; std::vector 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(), std::vector()); 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(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(PP_FLASH_CLIPBOARD_FORMAT_INVALID), format_id); // Make sure the format doesn't collide with predefined formats. ASSERT_NE(static_cast(PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT), format_id); ASSERT_NE(static_cast(PP_FLASH_CLIPBOARD_FORMAT_HTML), format_id); ASSERT_NE(static_cast(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, "")); 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(custom_data.size())); char* bytes = static_cast(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 formats_vector(1, format_id); std::vector 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(), std::vector()); sequence_number_after = GetSequenceNumber(sequence_number_before); ASSERT_NE(sequence_number_before, sequence_number_after); PASS(); }