chromium/ios/chrome/browser/main/model/browser_web_state_list_delegate_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/main/model/browser_web_state_list_delegate.h"

#import <tuple>

#import "ios/chrome/browser/sessions/model/ios_chrome_session_tab_helper.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/web/public/test/fakes/fake_web_frames_manager.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"

namespace {

// Forward-declaration of a tab helper. This is used as a way to check
// whether `AttachTabHelpers(...)` is called, but the tests themselves
// don't depend on a specific tab helper. Using an alias allow to change
// how the check is performed if in the future `AttachTabHelpers(...)`
// is modified.
using ExpectedTabHelper = IOSChromeSessionTabHelper;

using BrowserWebStateListDelegateTestParam =
    std::tuple<BrowserWebStateListDelegate::InsertionPolicy,
               BrowserWebStateListDelegate::ActivationPolicy>;

// List all ContentWorlds. Necessary because calling SetWebFramesManager(...)
// with a kAllContentWorlds is not enough with FakeWebState.
constexpr web::ContentWorld kContentWorlds[] = {
    web::ContentWorld::kAllContentWorlds,
    web::ContentWorld::kPageContentWorld,
    web::ContentWorld::kIsolatedWorld,
};

}  // namespace

class BrowserWebStateListDelegateTest
    : public testing::TestWithParam<BrowserWebStateListDelegateTestParam> {
 public:
  BrowserWebStateListDelegateTest() {
    browser_state_ = TestChromeBrowserState::Builder().Build();
    browser_state_->CreateOffTheRecordBrowserStateWithTestingFactories();
  }

  // Creates a fake WebState that is unrealized and off-the-record (this
  // reduces the number of tab helpers that are attached, avoiding those
  // that depends on KeyedService not created during testing).
  std::unique_ptr<web::WebState> CreateWebState() {
    auto web_state = std::make_unique<web::FakeWebState>();
    web_state->SetIsRealized(false);
    web_state->SetBrowserState(
        browser_state_->GetOffTheRecordChromeBrowserState());

    for (const web::ContentWorld content_world : kContentWorlds) {
      web_state->SetWebFramesManager(
          content_world, std::make_unique<web::FakeWebFramesManager>());
    }
    return web_state;
  }

 private:
  web::WebTaskEnvironment task_environment_;
  std::unique_ptr<TestChromeBrowserState> browser_state_;
};

INSTANTIATE_TEST_SUITE_P(
    BrowserWebStateListDelegateTestWithPolicies,
    BrowserWebStateListDelegateTest,
    ::testing::Combine(
        ::testing::Values(
            BrowserWebStateListDelegate::InsertionPolicy::kDoNothing,
            BrowserWebStateListDelegate::InsertionPolicy::kAttachTabHelpers),
        ::testing::Values(
            BrowserWebStateListDelegate::ActivationPolicy::kDoNothing,
            BrowserWebStateListDelegate::ActivationPolicy::kForceRealization)));

// Tests that BrowserWebStateListDelegateTest respects the InsertionPolicy
// when a WebState is inserted.
TEST_P(BrowserWebStateListDelegateTest, InsertionPolicy) {
  const BrowserWebStateListDelegateTestParam param = GetParam();
  BrowserWebStateListDelegate delegate(std::get<0>(param), std::get<1>(param));

  std::unique_ptr<web::WebState> web_state = CreateWebState();
  ASSERT_FALSE(web_state->IsRealized());
  ASSERT_FALSE(ExpectedTabHelper::FromWebState(web_state.get()));

  // Check that only the InsertionPolicy controls whether the tab helpers
  // are attached to a tab on insertion.
  delegate.WillAddWebState(web_state.get());
  switch (std::get<0>(param)) {
    case BrowserWebStateListDelegate::InsertionPolicy::kDoNothing:
      EXPECT_FALSE(web_state->IsRealized());
      EXPECT_FALSE(ExpectedTabHelper::FromWebState(web_state.get()));
      break;

    case BrowserWebStateListDelegate::InsertionPolicy::kAttachTabHelpers:
      EXPECT_FALSE(web_state->IsRealized());
      EXPECT_TRUE(ExpectedTabHelper::FromWebState(web_state.get()));
      break;
  }
}

// Tests that BrowserWebStateListDelegateTest respects the ActivationPolicy
// when a WebState is marked as the active one.
TEST_P(BrowserWebStateListDelegateTest, ActivationPolicy) {
  const BrowserWebStateListDelegateTestParam param = GetParam();
  BrowserWebStateListDelegate delegate(std::get<0>(param), std::get<1>(param));

  std::unique_ptr<web::WebState> web_state = CreateWebState();
  ASSERT_FALSE(web_state->IsRealized());
  ASSERT_FALSE(ExpectedTabHelper::FromWebState(web_state.get()));

  // Check that only the ActivationPolicy controls whether the WebState is
  // forced to the realized state when marked as the active one.
  delegate.WillActivateWebState(web_state.get());
  switch (std::get<1>(param)) {
    case BrowserWebStateListDelegate::ActivationPolicy::kDoNothing:
      EXPECT_FALSE(web_state->IsRealized());
      EXPECT_FALSE(ExpectedTabHelper::FromWebState(web_state.get()));
      break;

    case BrowserWebStateListDelegate::ActivationPolicy::kForceRealization:
      EXPECT_TRUE(web_state->IsRealized());
      EXPECT_FALSE(ExpectedTabHelper::FromWebState(web_state.get()));
      break;
  }
}