chromium/ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_mediator_unittest.mm

// 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.

#import "ios/chrome/browser/bring_android_tabs/ui_bundled/tab_list_from_android_mediator.h"

#import "base/memory/raw_ptr.h"
#import "base/test/metrics/histogram_tester.h"
#import "components/segmentation_platform/embedder/default_model/device_switcher_result_dispatcher.h"
#import "ios/chrome/browser/bring_android_tabs/model/bring_android_tabs_to_ios_service.h"
#import "ios/chrome/browser/bring_android_tabs/model/fake_bring_android_tabs_to_ios_service.h"
#import "ios/chrome/browser/bring_android_tabs/model/metrics.h"
#import "ios/chrome/browser/favicon/model/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/segmentation_platform/model/segmentation_platform_service_factory.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/chrome/browser/sync/model/session_sync_service_factory.h"
#import "ios/chrome/browser/sync/model/sync_service_factory.h"
#import "ios/chrome/browser/synced_sessions/model/distant_tab.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/platform_test.h"
#import "url/gurl.h"

namespace {
const std::vector<std::string> kTestUrls{
    "http://chromium.org", "http://google.com", "http://example.com"};
}  // namespace

// Test fixture for TabListFromAndroidMediator.
class TabListFromAndroidMediatorTest : public PlatformTest {
 protected:
  TabListFromAndroidMediatorTest() : PlatformTest() {
    SetUpEnvironment();
    CreateBringAndroidTabsToIOSService();
    CreateMediator();
  }

  // Sets up the environment.
  void SetUpEnvironment() {
    TestChromeBrowserState::Builder builder;
    builder.AddTestingFactory(
        segmentation_platform::SegmentationPlatformServiceFactory::
            GetInstance(),
        segmentation_platform::SegmentationPlatformServiceFactory::
            GetDefaultFactory());
    browser_state_ = std::move(builder).Build();
  }

  // Creates the set of tabs to pass to the FakeBringAndroidTabsToIOSService and
  // open.
  std::vector<std::unique_ptr<synced_sessions::DistantTab>> SetOfTabs() {
    std::vector<std::unique_ptr<synced_sessions::DistantTab>> tabs;
    for (std::string url : kTestUrls) {
      std::unique_ptr<synced_sessions::DistantTab> tab =
          std::make_unique<synced_sessions::DistantTab>();
      tab->virtual_url = GURL(url);
      tabs.push_back(std::move(tab));
    }
    return tabs;
  }

  // Creates the fake BringAndroidTabsToIOSService that takes a set of tabs as
  // input.
  void CreateBringAndroidTabsToIOSService() {
    segmentation_platform::DeviceSwitcherResultDispatcher* dispatcher =
        segmentation_platform::SegmentationPlatformServiceFactory::
            GetDispatcherForBrowserState(browser_state_.get());
    syncer::SyncService* sync_service =
        SyncServiceFactory::GetForBrowserState(browser_state_.get());
    sync_sessions::SessionSyncService* session_sync_service =
        SessionSyncServiceFactory::GetForBrowserState(browser_state_.get());
    PrefService* prefs = browser_state_->GetPrefs();
    fake_bring_android_tabs_service_ = new FakeBringAndroidTabsToIOSService(
        SetOfTabs(), dispatcher, sync_service, session_sync_service, prefs);
  }

  // Creates the mediator.
  void CreateMediator() {
    mediator_ = [[TabListFromAndroidMediator alloc]
        initWithBringAndroidTabsService:fake_bring_android_tabs_service_
                              URLLoader:nullptr
                          faviconLoader:IOSChromeFaviconLoaderFactory::
                                            GetForBrowserState(
                                                browser_state_.get())];
  }

 protected:
  // Environment mocks.
  web::WebTaskEnvironment task_environment_;
  raw_ptr<FakeBringAndroidTabsToIOSService> fake_bring_android_tabs_service_;
  // Mediator dependencies.
  std::unique_ptr<TestChromeBrowserState> browser_state_;
  TabListFromAndroidMediator* mediator_;
};

// Tests when the user taps "open", the mediator logs histogram and opens tabs
// on request.
TEST_F(TabListFromAndroidMediatorTest, DeselectAndOpenTabs) {
  base::HistogramTester histogram_tester;
  NSArray* array = @[ @0, @2 ];
  [mediator_
      tabListFromAndroidViewControllerDidTapOpenButtonWithTabIndices:array];

  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kTabListActionHistogramName,
      bring_android_tabs::TabsListActionType::kOpenTabs, 1);
  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kDeselectedTabCountHistogramName, 1, 1);

  // Check that the correct tabs are opened.
  std::vector<size_t> opened_tabs =
      fake_bring_android_tabs_service_->opened_tabs_at_indices();
  ASSERT_EQ(opened_tabs.size(), 2u);
  EXPECT_EQ(opened_tabs[0], 0u);
  EXPECT_EQ(opened_tabs[1], 2u);
}

// Tests that the mediator logs histogram when the user taps the cancel button.
TEST_F(TabListFromAndroidMediatorTest, TapCancelButton) {
  base::HistogramTester histogram_tester;
  [mediator_ tabListFromAndroidViewControllerDidDismissWithSwipe:NO
                                          numberOfDeselectedTabs:10];
  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kTabListActionHistogramName,
      bring_android_tabs::TabsListActionType::kCancel, 1);
  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kDeselectedTabCountHistogramName, 10, 1);
  EXPECT_EQ(fake_bring_android_tabs_service_->opened_tabs_at_indices().size(),
            0u);
}

// Tests that the mediator logs histogram when the user swipes down to dismiss
// the table.
TEST_F(TabListFromAndroidMediatorTest, SwipeToDismiss) {
  base::HistogramTester histogram_tester;
  [mediator_ tabListFromAndroidViewControllerDidDismissWithSwipe:YES
                                          numberOfDeselectedTabs:5];
  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kTabListActionHistogramName,
      bring_android_tabs::TabsListActionType::kSwipeDown, 1);
  histogram_tester.ExpectUniqueSample(
      bring_android_tabs::kDeselectedTabCountHistogramName, 5, 1);
  EXPECT_EQ(fake_bring_android_tabs_service_->opened_tabs_at_indices().size(),
            0u);
}