blob: 84aaeb6cc6fbc2a31f0612af98a6e9afa03507de [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/snapshots/model/snapshot_browser_agent.h"
#import <UIKit/UIKit.h>
#import "base/functional/bind.h"
#import "base/functional/callback_helpers.h"
#import "base/run_loop.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/snapshots/model/fake_snapshot_generator_delegate.h"
#import "ios/chrome/browser/snapshots/model/model_swift.h"
#import "ios/chrome/browser/snapshots/model/snapshot_source_tab_helper.h"
#import "ios/chrome/browser/snapshots/model/snapshot_tab_helper.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
namespace {
// Name of the directory where snapshots are saved.
const char kIdentifier[] = "Identifier";
// Converts `snapshot_id` to a SnapshotIDWrapper.
SnapshotIDWrapper* ToWrapper(SnapshotID snapshot_id) {
return [[SnapshotIDWrapper alloc] initWithSnapshotID:snapshot_id];
}
// Returns a callback that capture its argument and store it to `output`.
template <typename T>
base::OnceCallback<void(T)> CaptureArg(T& output) {
return base::BindOnce([](T& output, T arg) { output = arg; },
std::ref(output));
}
} // anonymous namespace
class SnapshotBrowserAgentTest : public PlatformTest {
public:
SnapshotBrowserAgentTest() {
profile_ = TestProfileIOS::Builder().Build();
browser_ = std::make_unique<TestBrowser>(profile_.get());
// Configure the FakeSnapshotGeneratorDelegate with a fake view. This
// allow to capture snapshot with a fake WebState.
delegate_ = [[FakeSnapshotGeneratorDelegate alloc] init];
UIView* view = [[UIView alloc] initWithFrame:{{0, 0}, {300, 400}}];
view.backgroundColor = [UIColor redColor];
delegate_.view = view;
}
// Create a fake WebState that is configured to take snapshot using the
// fake SnapshotGeneratorDelegate.
std::unique_ptr<web::WebState> CreateWebState() {
auto web_state = std::make_unique<web::FakeWebState>();
SnapshotTabHelper::CreateForWebState(web_state.get());
SnapshotSourceTabHelper::CreateForWebState(web_state.get());
SnapshotTabHelper::FromWebState(web_state.get())->SetDelegate(delegate_);
return web_state;
}
// Updates snapshot for WebState and returns it.
UIImage* UpdateSnapshotForWebState(web::WebState* web_state) {
UIImage* result = nil;
base::RunLoop run_loop;
SnapshotTabHelper::FromWebState(web_state)->UpdateSnapshotWithCallback(
base::CallbackToBlock(
base::BindOnce(CaptureArg(result)).Then(run_loop.QuitClosure())));
run_loop.Run();
return result;
}
// Retrieves an image from the storage (or null if it is not present).
UIImage* RetrieveImageFromStorage(SnapshotID snapshot_id) {
auto* storage =
SnapshotBrowserAgent::FromBrowser(browser_.get())->snapshot_storage();
UIImage* result = nil;
base::RunLoop run_loop;
[storage retrieveImageWithSnapshotID:ToWrapper(snapshot_id)
snapshotKind:SnapshotKindColor
completion:base::CallbackToBlock(
CaptureArg(result).Then(
run_loop.QuitClosure()))];
run_loop.Run();
return result;
}
protected:
web::WebTaskEnvironment task_environment_;
std::unique_ptr<TestProfileIOS> profile_;
std::unique_ptr<Browser> browser_;
FakeSnapshotGeneratorDelegate* delegate_;
};
TEST_F(SnapshotBrowserAgentTest, SnapshotStorageCreatedAfterSettingSessionID) {
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent* agent =
SnapshotBrowserAgent::FromBrowser(browser_.get());
EXPECT_NE(nullptr, agent);
EXPECT_EQ(nil, agent->snapshot_storage());
agent->SetSessionID(kIdentifier);
EXPECT_NE(nil, agent->snapshot_storage());
}
// Tests that snapshots are deleted when a tab is closed by the user.
TEST_F(SnapshotBrowserAgentTest, SnapshotDeletedWhenTabClosedByUser) {
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
// Create a fake WebState and insert it in the Browser's WebStateList.
browser_->GetWebStateList()->InsertWebState(CreateWebState());
ASSERT_EQ(browser_->GetWebStateList()->count(), 1);
// Generate the snapshot for the web_state.
web::WebState* web_state = browser_->GetWebStateList()->GetWebStateAt(0);
const SnapshotID snapshot_id(web_state->GetUniqueIdentifier());
UIImage* image = UpdateSnapshotForWebState(web_state);
ASSERT_NSNE(image, nil);
// The snapshot should now be retrievable from the storage.
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
// Pretend the user closed the WebState and check that the image has been
// removed from the storage.
const auto close_reason = WebStateList::ClosingReason::kUserAction;
browser_->GetWebStateList()->CloseWebStateAt(0, close_reason);
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), nil);
}
// Tests that snapshots are deleted when a tab is closed for cleanup.
TEST_F(SnapshotBrowserAgentTest, SnapshotDeletedWhenTabClosedForCleanup) {
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
// Create a fake WebState and insert it in the Browser's WebStateList.
browser_->GetWebStateList()->InsertWebState(CreateWebState());
ASSERT_EQ(browser_->GetWebStateList()->count(), 1);
// Generate the snapshot for the web_state.
web::WebState* web_state = browser_->GetWebStateList()->GetWebStateAt(0);
const SnapshotID snapshot_id(web_state->GetUniqueIdentifier());
UIImage* image = UpdateSnapshotForWebState(web_state);
ASSERT_NSNE(image, nil);
// The snapshot should now be retrievable from the storage.
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
// Pretend the user closed the WebState and check that the image has been
// removed from the storage.
const auto close_reason = WebStateList::ClosingReason::kTabsCleanup;
browser_->GetWebStateList()->CloseWebStateAt(0, close_reason);
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), nil);
}
// Tests that snapshots are not deleted when a tab is closed automatically.
TEST_F(SnapshotBrowserAgentTest, SnapshotNotDeletedWhenTabClosedWithNoFlags) {
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
// Create a fake WebState and insert it in the Browser's WebStateList.
browser_->GetWebStateList()->InsertWebState(CreateWebState());
ASSERT_EQ(browser_->GetWebStateList()->count(), 1);
// Generate the snapshot for the web_state.
web::WebState* web_state = browser_->GetWebStateList()->GetWebStateAt(0);
const SnapshotID snapshot_id(web_state->GetUniqueIdentifier());
UIImage* image = UpdateSnapshotForWebState(web_state);
ASSERT_NSNE(image, nil);
// The snapshot should now be retrievable from the storage.
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
// Pretend the user closed the WebState and check that the image has been
// removed from the storage.
const auto close_reason = WebStateList::ClosingReason::kDefault;
browser_->GetWebStateList()->CloseWebStateAt(0, close_reason);
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
}
// Tests that snapshots are not deleted when a tab is detached.
TEST_F(SnapshotBrowserAgentTest, SnapshotNotDeletedWhenTabDetached) {
SnapshotBrowserAgent::CreateForBrowser(browser_.get());
SnapshotBrowserAgent::FromBrowser(browser_.get())->SetSessionID(kIdentifier);
// Create a fake WebState and insert it in the Browser's WebStateList.
browser_->GetWebStateList()->InsertWebState(CreateWebState());
ASSERT_EQ(browser_->GetWebStateList()->count(), 1);
// Generate the snapshot for the web_state.
web::WebState* web_state = browser_->GetWebStateList()->GetWebStateAt(0);
const SnapshotID snapshot_id(web_state->GetUniqueIdentifier());
UIImage* image = UpdateSnapshotForWebState(web_state);
ASSERT_NSNE(image, nil);
// The snapshot should now be retrievable from the storage.
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
// Pretend the user closed the WebState and check that the image has been
// removed from the storage.
auto detached_web_state = browser_->GetWebStateList()->DetachWebStateAt(0);
EXPECT_NSEQ(RetrieveImageFromStorage(snapshot_id), image);
}