blob: 714296013a5eb2327a53628969af5c9f9e9fc876 [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/ui/webui/tab_strip/thumbnail_tracker.h"
#include <map>
#include <memory>
#include <utility>
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/thumbnails/thumbnail_image.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace {
class TestThumbnailImageDelegate : public ThumbnailImage::Delegate {
public:
TestThumbnailImageDelegate() = default;
~TestThumbnailImageDelegate() override = default;
void ThumbnailImageBeingObservedChanged(bool is_being_observed) override {}
};
class ThumbnailTrackerTest : public ::testing::Test,
public ThumbnailImage::Delegate {
protected:
ThumbnailTrackerTest()
: thumbnail_tracker_(
thumbnail_updated_callback_.Get(),
base::Bind(&ThumbnailTrackerTest::GetTestingThumbnail,
base::Unretained(this))) {}
static SkBitmap CreateTestingBitmap() {
SkBitmap bitmap;
bitmap.allocN32Pixels(1, 1, true);
bitmap.eraseColor(SK_ColorBLACK);
bitmap.setImmutable();
return bitmap;
}
std::unique_ptr<content::WebContents> CreateWebContents() {
auto contents =
content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
SessionTabHelper::CreateForWebContents(contents.get());
return contents;
}
scoped_refptr<ThumbnailImage> GetTestingThumbnail(
content::WebContents* contents) {
return tab_thumbnails_[contents].thumbnail_image;
}
// ThumbnailImage::Delegate:
void ThumbnailImageBeingObservedChanged(bool is_being_observed) override {}
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
base::MockCallback<ThumbnailTracker::ThumbnailUpdatedCallback>
thumbnail_updated_callback_;
struct ThumbnailData {
ThumbnailData()
: thumbnail_image(base::MakeRefCounted<ThumbnailImage>(&delegate)) {}
TestThumbnailImageDelegate delegate;
scoped_refptr<ThumbnailImage> thumbnail_image;
};
std::map<content::WebContents*, ThumbnailData> tab_thumbnails_;
ThumbnailTracker thumbnail_tracker_;
};
} // namespace
using ::testing::_;
TEST_F(ThumbnailTrackerTest, WatchTabGetsCurrentThumbnail) {
auto contents = CreateWebContents();
auto thumbnail = GetTestingThumbnail(contents.get());
// Set the thumbnail image and wait for it to be stored.
base::RunLoop encode_loop;
thumbnail->set_async_operation_finished_callback_for_testing(
encode_loop.QuitClosure());
thumbnail->AssignSkBitmap(CreateTestingBitmap());
encode_loop.Run();
// Verify that WatchTab() gets the current image, waiting for the decoding to
// happen.
EXPECT_CALL(thumbnail_updated_callback_, Run(contents.get(), _)).Times(1);
thumbnail->set_async_operation_finished_callback_for_testing(
base::RepeatingClosure());
thumbnail_tracker_.WatchTab(contents.get());
}
TEST_F(ThumbnailTrackerTest, PropagatesThumbnailUpdate) {
auto contents1 = CreateWebContents();
auto thumbnail1 = GetTestingThumbnail(contents1.get());
auto contents2 = CreateWebContents();
auto thumbnail2 = GetTestingThumbnail(contents2.get());
// Since no thumbnail image exists yet, this shouldn't notify our callback.
thumbnail_tracker_.WatchTab(contents1.get());
thumbnail_tracker_.WatchTab(contents2.get());
{
::testing::InSequence seq;
EXPECT_CALL(thumbnail_updated_callback_, Run(contents1.get(), _)).Times(1);
EXPECT_CALL(thumbnail_updated_callback_, Run(contents2.get(), _)).Times(1);
}
base::RunLoop first_update_loop;
thumbnail1->set_async_operation_finished_callback_for_testing(
first_update_loop.QuitClosure());
thumbnail1->AssignSkBitmap(CreateTestingBitmap());
first_update_loop.Run();
base::RunLoop second_update_loop;
thumbnail2->set_async_operation_finished_callback_for_testing(
second_update_loop.QuitClosure());
thumbnail2->AssignSkBitmap(CreateTestingBitmap());
second_update_loop.Run();
}
TEST_F(ThumbnailTrackerTest, StopsObservingOnTabClose) {
auto contents = CreateWebContents();
auto thumbnail = GetTestingThumbnail(contents.get());
thumbnail_tracker_.WatchTab(contents.get());
// |thumbnail| is still valid, but |thumbnail_tracker_| should stop watching
// it when |contents| goes away.
EXPECT_CALL(thumbnail_updated_callback_, Run(_, _)).Times(0);
contents.reset();
base::RunLoop update_loop;
thumbnail->set_async_operation_finished_callback_for_testing(
update_loop.QuitClosure());
thumbnail->AssignSkBitmap(CreateTestingBitmap());
update_loop.Run();
}