blob: 16556e49903d59234c2833cf8e61870aaeb2807e [file] [log] [blame]
// Copyright 2014 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 "content/browser/renderer_host/clipboard_host_impl.h"
#include <stddef.h>
#include <stdint.h>
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/test/bind_test_util.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/test/test_clipboard.h"
#include "ui/gfx/skia_util.h"
namespace content {
class ClipboardHostImplTest : public ::testing::Test {
protected:
ClipboardHostImplTest()
: clipboard_(ui::TestClipboard::CreateForCurrentThread()) {
ClipboardHostImpl::Create(mojo::MakeRequest(&ptr_));
}
~ClipboardHostImplTest() override {
ui::Clipboard::DestroyClipboardForCurrentThread();
}
blink::mojom::ClipboardHostPtr& mojo_clipboard() { return ptr_; }
ui::Clipboard* system_clipboard() { return clipboard_; }
private:
const TestBrowserThreadBundle thread_bundle_;
blink::mojom::ClipboardHostPtr ptr_;
ui::Clipboard* const clipboard_;
};
// Test that it actually works.
TEST_F(ClipboardHostImplTest, SimpleImage) {
SkBitmap bitmap;
bitmap.allocN32Pixels(3, 2);
bitmap.eraseARGB(255, 0, 255, 0);
mojo_clipboard()->WriteImage(ui::CLIPBOARD_TYPE_COPY_PASTE, bitmap);
uint64_t sequence_number =
system_clipboard()->GetSequenceNumber(ui::CLIPBOARD_TYPE_COPY_PASTE);
mojo_clipboard()->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
base::RunLoop().RunUntilIdle();
EXPECT_NE(sequence_number, system_clipboard()->GetSequenceNumber(
ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_FALSE(system_clipboard()->IsFormatAvailable(
ui::Clipboard::GetPlainTextFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
EXPECT_TRUE(system_clipboard()->IsFormatAvailable(
ui::Clipboard::GetBitmapFormatType(), ui::CLIPBOARD_TYPE_COPY_PASTE));
SkBitmap actual =
system_clipboard()->ReadImage(ui::CLIPBOARD_TYPE_COPY_PASTE);
EXPECT_TRUE(gfx::BitmapsAreEqual(bitmap, actual));
}
TEST_F(ClipboardHostImplTest, ReentrancyInSyncCall) {
// Due to the nature of this test, it's somewhat racy. On some platforms
// (currently Linux), reading the clipboard requires running a nested message
// loop. During that time, it's possible to send a bad message that causes the
// message pipe to be closed. Make sure ClipboardHostImpl doesn't UaF |this|
// after exiting the nested message loop.
// ReadText() is a sync method, so normally, one wouldn't call this method
// directly. These are not normal times though...
mojo_clipboard()->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, base::DoNothing());
// Now purposely write a raw message which (hopefully) won't deserialize to
// anything valid. The receiver side should still be in the midst of
// dispatching ReadText() when Mojo attempts to deserialize this message,
// which should cause a validation failure that signals a connection error.
base::RunLoop run_loop;
mojo::WriteMessageRaw(mojo_clipboard().internal_state()->handle(), "moo", 3,
nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
mojo_clipboard().set_connection_error_handler(run_loop.QuitClosure());
run_loop.Run();
EXPECT_TRUE(mojo_clipboard().encountered_error());
}
} // namespace content