chromium/chrome/browser/sync/glue/synced_tab_delegate_android_unittest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/browser/sync/glue/synced_tab_delegate_android.h"

#include <cstddef>
#include <cstdint>
#include <memory>

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/android/tab_android_data_provider.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/sessions/core/session_id.h"
#include "components/sync/protocol/sync_enums.pb.h"
#include "components/sync_sessions/features.h"
#include "components/sync_sessions/mock_sync_sessions_client.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

namespace browser_sync {

namespace {

using testing::_;

using testing::Mock;
using testing::Return;

class MockTabAndroidDataProvider : public TabAndroidDataProvider {
 public:
  MOCK_METHOD(SessionID, GetWindowId, (), (const override));
  MOCK_METHOD(int, GetAndroidId, (), (const override));
  MOCK_METHOD(std::unique_ptr<WebContentsStateByteBuffer>,
              GetWebContentsByteBuffer,
              (),
              (override));
};

const bool kIsOffTheRecord = false;
const int kVersion = 2;
const url::Origin kInitiatorOrigin;

class SyncedTabDelegateAndroidTest : public testing::Test {
 protected:
  void SetUp() override {
    CHECK(profile_manager_.SetUp());
    profile_ = TestingProfile::Builder().Build();

    Mock::VerifyAndClear(&mock_sync_sessions_client_);
    ON_CALL(mock_sync_sessions_client_, ShouldSyncURL(GURL(kInterestingUrl)))
        .WillByDefault(Return(true));
    ON_CALL(mock_sync_sessions_client_, ShouldSyncURL(GURL(kBoringUrl)))
        .WillByDefault(Return(false));
  }

  void MockBufferFromPickle(const base::Pickle& pickle) {
    base::raw_span<const uint8_t> nav_span{pickle.data(), pickle.size()};
    std::unique_ptr<WebContentsStateByteBuffer> buffer =
        std::make_unique<WebContentsStateByteBuffer>(nav_span, kVersion);
    EXPECT_CALL(mock_tab_android_data_provider_, GetWebContentsByteBuffer())
        .WillOnce(Return(std::move(buffer)));
  }

  const std::u16string kTitle = u"";
  const GURL kInterestingUrl = GURL("fake://interesting");
  const GURL kBoringUrl = GURL("fake://boring");
  const content::Referrer kReferrer =
      content::Referrer(GURL(""), network::mojom::ReferrerPolicy::kDefault);

  content::BrowserTaskEnvironment task_environment_;
  base::test::ScopedFeatureList feature_list_;
  TestingProfileManager profile_manager_ =
      TestingProfileManager(TestingBrowserProcess::GetGlobal());
  std::unique_ptr<TestingProfile> profile_;
  testing::NiceMock<sync_sessions::MockSyncSessionsClient>
      mock_sync_sessions_client_;
  testing::NiceMock<MockTabAndroidDataProvider> mock_tab_android_data_provider_;
  SyncedTabDelegateAndroid synced_tab_delegate_android_ =
      SyncedTabDelegateAndroid(&mock_tab_android_data_provider_);
};

TEST_F(SyncedTabDelegateAndroidTest, ReadPlaceholderNullBuffer) {
  EXPECT_CALL(mock_tab_android_data_provider_, GetWebContentsByteBuffer())
      .WillOnce(Return(nullptr));

  std::unique_ptr<sync_sessions::SyncedTabDelegate> placeholder =
      synced_tab_delegate_android_.ReadPlaceholderTabSnapshotIfItShouldSync(
          &mock_sync_sessions_client_);

  EXPECT_EQ(nullptr, placeholder.get());
}

TEST_F(SyncedTabDelegateAndroidTest, ReadPlaceholderBoring) {
  base::Pickle pickle = WebContentsState::CreateSingleNavigationStateAsPickle(
      kTitle, kBoringUrl, kReferrer, kInitiatorOrigin, kIsOffTheRecord);
  MockBufferFromPickle(pickle);

  std::unique_ptr<sync_sessions::SyncedTabDelegate> placeholder =
      synced_tab_delegate_android_.ReadPlaceholderTabSnapshotIfItShouldSync(
          &mock_sync_sessions_client_);

  EXPECT_NE(nullptr, placeholder.get());
}

TEST_F(SyncedTabDelegateAndroidTest, ReadPlaceholderBoringWithOptimization) {
  feature_list_.InitAndEnableFeature(
      sync_sessions::kOptimizeAssociateWindowsAndroid);
  base::Pickle pickle = WebContentsState::CreateSingleNavigationStateAsPickle(
      kTitle, kBoringUrl, kReferrer, kInitiatorOrigin, kIsOffTheRecord);
  MockBufferFromPickle(pickle);

  std::unique_ptr<sync_sessions::SyncedTabDelegate> placeholder =
      synced_tab_delegate_android_.ReadPlaceholderTabSnapshotIfItShouldSync(
          &mock_sync_sessions_client_);

  EXPECT_EQ(nullptr, placeholder.get());
}

TEST_F(SyncedTabDelegateAndroidTest,
       ReadPlaceholderInterestingWithOptimization) {
  feature_list_.InitAndEnableFeature(
      sync_sessions::kOptimizeAssociateWindowsAndroid);
  base::Pickle pickle = WebContentsState::CreateSingleNavigationStateAsPickle(
      kTitle, kInterestingUrl, kReferrer, kInitiatorOrigin, kIsOffTheRecord);
  MockBufferFromPickle(pickle);

  std::unique_ptr<sync_sessions::SyncedTabDelegate> placeholder =
      synced_tab_delegate_android_.ReadPlaceholderTabSnapshotIfItShouldSync(
          &mock_sync_sessions_client_);

  EXPECT_NE(nullptr, placeholder.get());
}

}  // namespace

}  // namespace browser_sync