| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/sync/synced_session_client_ash.h" |
| |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "base/test/test_future.h" |
| #include "base/time/time.h" |
| #include "chromeos/crosapi/mojom/synced_session_client.mojom.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/favicon_size.h" |
| #include "ui/gfx/image/image_unittest_util.h" |
| #include "url/gurl.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr char kTestSessionName[] = "testing"; |
| constexpr char kTestUrl[] = "www.google.com"; |
| constexpr char16_t kTestTitle[] = u"helloworld"; |
| constexpr base::Time kTestModifiedTime = base::Time::FromTimeT(100); |
| constexpr base::Time kTestLastModifiedTimestamp = base::Time::FromTimeT(200); |
| |
| std::vector<crosapi::mojom::SyncedSessionPtr> CreateTestSyncedSessions() { |
| std::vector<crosapi::mojom::SyncedSessionPtr> test_sessions; |
| crosapi::mojom::SyncedSessionPtr test_session = |
| crosapi::mojom::SyncedSession::New(); |
| test_session->session_name = kTestSessionName; |
| test_session->modified_time = kTestModifiedTime; |
| crosapi::mojom::SyncedSessionWindowPtr test_window = |
| crosapi::mojom::SyncedSessionWindow::New(); |
| crosapi::mojom::SyncedSessionTabPtr test_tab = |
| crosapi::mojom::SyncedSessionTab::New(); |
| test_tab->current_navigation_url = GURL(kTestUrl); |
| test_tab->last_modified_timestamp = kTestLastModifiedTimestamp; |
| test_tab->current_navigation_title = kTestTitle; |
| test_window->tabs.push_back(std::move(test_tab)); |
| test_session->windows.push_back(std::move(test_window)); |
| test_sessions.push_back(std::move(test_session)); |
| return test_sessions; |
| } |
| |
| class TestSyncedSessionClientObserver |
| : public SyncedSessionClientAsh::Observer { |
| public: |
| TestSyncedSessionClientObserver() = default; |
| TestSyncedSessionClientObserver(const TestSyncedSessionClientObserver&) = |
| delete; |
| TestSyncedSessionClientObserver& operator=( |
| const TestSyncedSessionClientObserver&) = delete; |
| ~TestSyncedSessionClientObserver() override = default; |
| |
| void OnForeignSyncedPhoneSessionsUpdated( |
| const std::vector<ForeignSyncedSessionAsh>& sessions) override { |
| read_sessions_ = sessions; |
| } |
| |
| void OnSessionSyncEnabledChanged(bool enabled) override { |
| is_session_sync_enabled_ = enabled; |
| } |
| |
| const std::vector<ForeignSyncedSessionAsh>& GetLastReadSessions() const { |
| return read_sessions_; |
| } |
| |
| bool IsSessionSyncEnabled() const { return is_session_sync_enabled_; } |
| |
| private: |
| std::vector<ForeignSyncedSessionAsh> read_sessions_; |
| bool is_session_sync_enabled_ = false; |
| }; |
| |
| class FakeCrosapiSessionSyncFaviconDelegate |
| : public crosapi::mojom::SyncedSessionClientFaviconDelegate { |
| public: |
| FakeCrosapiSessionSyncFaviconDelegate() = default; |
| FakeCrosapiSessionSyncFaviconDelegate( |
| const FakeCrosapiSessionSyncFaviconDelegate&) = delete; |
| FakeCrosapiSessionSyncFaviconDelegate& operator=( |
| const FakeCrosapiSessionSyncFaviconDelegate&) = delete; |
| ~FakeCrosapiSessionSyncFaviconDelegate() override = default; |
| |
| // crosapi::mojom::SyncedSessionClientFaviconDelegate: |
| void GetFaviconImageForPageURL( |
| const GURL& url, |
| GetFaviconImageForPageURLCallback callback) override { |
| std::move(callback).Run(*result_image_); |
| } |
| |
| mojo::PendingRemote<crosapi::mojom::SyncedSessionClientFaviconDelegate> |
| CreateRemote() { |
| return receiver_.BindNewPipeAndPassRemote(); |
| } |
| |
| void SetResultImage(gfx::ImageSkia* image) { result_image_ = image; } |
| |
| private: |
| mojo::Receiver<crosapi::mojom::SyncedSessionClientFaviconDelegate> receiver_{ |
| this}; |
| gfx::ImageSkia* result_image_ = nullptr; |
| }; |
| |
| gfx::ImageSkia GetTestImage() { |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize); |
| bitmap.eraseColor(SK_ColorBLUE); |
| return gfx::Image::CreateFrom1xBitmap(bitmap).AsImageSkia(); |
| } |
| |
| } // namespace |
| |
| class SyncedSessionClientAshTest : public testing::Test { |
| public: |
| SyncedSessionClientAshTest() = default; |
| SyncedSessionClientAshTest(const SyncedSessionClientAshTest&) = delete; |
| SyncedSessionClientAshTest& operator=(const SyncedSessionClientAshTest&) = |
| delete; |
| ~SyncedSessionClientAshTest() override = default; |
| |
| void SetUp() override { |
| client_ = std::make_unique<SyncedSessionClientAsh>(); |
| client_remote_.Bind(client_->CreateRemote()); |
| test_observer_ = std::make_unique<TestSyncedSessionClientObserver>(); |
| client_->AddObserver(test_observer_.get()); |
| } |
| |
| void RequestFaviconImage(gfx::ImageSkia expected_image) { |
| base::test::TestFuture<const gfx::ImageSkia&> future; |
| client_->GetFaviconImageForPageURL(GURL(kTestUrl), future.GetCallback()); |
| EXPECT_TRUE(gfx::test::AreImagesEqual(gfx::Image(expected_image), |
| gfx::Image(future.Get()))); |
| } |
| |
| SyncedSessionClientAsh* client() { |
| DCHECK(client_); |
| return client_.get(); |
| } |
| |
| mojo::Remote<crosapi::mojom::SyncedSessionClient>* client_remote() { |
| return &client_remote_; |
| } |
| |
| TestSyncedSessionClientObserver* test_observer() { |
| DCHECK(test_observer_); |
| return test_observer_.get(); |
| } |
| |
| private: |
| base::test::SingleThreadTaskEnvironment task_environment_; |
| |
| std::unique_ptr<SyncedSessionClientAsh> client_; |
| mojo::Remote<crosapi::mojom::SyncedSessionClient> client_remote_; |
| std::unique_ptr<TestSyncedSessionClientObserver> test_observer_; |
| }; |
| |
| TEST_F(SyncedSessionClientAshTest, OnForeignSyncedPhoneSessionsUpdated) { |
| client()->OnForeignSyncedPhoneSessionsUpdated(CreateTestSyncedSessions()); |
| std::vector<ForeignSyncedSessionAsh> observed_sessions = |
| test_observer()->GetLastReadSessions(); |
| ASSERT_EQ(observed_sessions.size(), 1u); |
| EXPECT_EQ(observed_sessions[0].session_name, kTestSessionName); |
| EXPECT_EQ(observed_sessions[0].modified_time, kTestModifiedTime); |
| ASSERT_EQ(observed_sessions[0].windows.size(), 1u); |
| ASSERT_EQ(observed_sessions[0].windows[0].tabs.size(), 1u); |
| EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].current_navigation_url, |
| GURL(kTestUrl)); |
| EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].last_modified_timestamp, |
| kTestLastModifiedTimestamp); |
| EXPECT_EQ(observed_sessions[0].windows[0].tabs[0].current_navigation_title, |
| kTestTitle); |
| } |
| |
| TEST_F(SyncedSessionClientAshTest, OnSessionSyncEnabledChanged) { |
| client()->OnSessionSyncEnabledChanged(/*enabled=*/true); |
| EXPECT_TRUE(test_observer()->IsSessionSyncEnabled()); |
| client()->OnSessionSyncEnabledChanged(/*enabled=*/false); |
| EXPECT_FALSE(test_observer()->IsSessionSyncEnabled()); |
| } |
| |
| TEST_F(SyncedSessionClientAshTest, GetFaviconImage_NoRemote) { |
| RequestFaviconImage(gfx::ImageSkia()); |
| } |
| |
| TEST_F(SyncedSessionClientAshTest, GetFaviconImage_ImagesMatch) { |
| FakeCrosapiSessionSyncFaviconDelegate favicon_delegate; |
| client()->SetFaviconDelegate(favicon_delegate.CreateRemote()); |
| |
| gfx::ImageSkia empty_image; |
| favicon_delegate.SetResultImage(&empty_image); |
| RequestFaviconImage(gfx::ImageSkia()); |
| |
| gfx::ImageSkia test_image = GetTestImage(); |
| favicon_delegate.SetResultImage(&test_image); |
| RequestFaviconImage(GetTestImage()); |
| } |
| |
| } // namespace ash |