chromium/ios/web/web_state/web_state_delegate_bridge_unittest.mm

// Copyright 2016 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/web/public/web_state_delegate_bridge.h"

#import <Foundation/Foundation.h>

#import <memory>

#import "base/functional/bind.h"
#import "base/functional/callback_helpers.h"
#import "base/strings/utf_string_conversions.h"
#import "ios/web/public/test/crw_fake_web_state_delegate.h"
#import "ios/web/public/test/fakes/fake_web_state.h"
#import "ios/web/public/ui/context_menu_params.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
#import "ui/base/page_transition_types.h"

// Class which conforms to CRWWebStateDelegate protocol, but does not implement
// any optional methods.
@interface TestEmptyWebStateDelegate : NSObject<CRWWebStateDelegate>
@end

@implementation TestEmptyWebStateDelegate
@end

namespace web {

// Test fixture to test WebStateDelegateBridge class.
class WebStateDelegateBridgeTest : public PlatformTest {
 protected:
  void SetUp() override {
    PlatformTest::SetUp();

    delegate_ = [[CRWFakeWebStateDelegate alloc] init];
    empty_delegate_ = [[TestEmptyWebStateDelegate alloc] init];

    bridge_.reset(new WebStateDelegateBridge(delegate_));
    empty_delegate_bridge_.reset(new WebStateDelegateBridge(empty_delegate_));
  }

  void TearDown() override {
    PlatformTest::TearDown();
  }

  CRWFakeWebStateDelegate* delegate_;
  id empty_delegate_;
  std::unique_ptr<WebStateDelegateBridge> bridge_;
  std::unique_ptr<WebStateDelegateBridge> empty_delegate_bridge_;
  web::FakeWebState fake_web_state_;
};

// Tests `webState:createNewWebStateForURL:openerURL:initiatedByUser:`
// forwarding.
TEST_F(WebStateDelegateBridgeTest, CreateNewWebState) {
  ASSERT_FALSE([delegate_ webState]);
  ASSERT_FALSE([delegate_ webStateCreationRequested]);

  EXPECT_FALSE(
      bridge_->CreateNewWebState(&fake_web_state_, GURL(), GURL(), true));

  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
  ASSERT_TRUE([delegate_ webStateCreationRequested]);
}

// Tests `closeWebState:` forwarding.
TEST_F(WebStateDelegateBridgeTest, CloseWebState) {
  ASSERT_FALSE([delegate_ webState]);
  ASSERT_FALSE([delegate_ webStateClosingRequested]);

  bridge_->CloseWebState(&fake_web_state_);

  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
  ASSERT_TRUE([delegate_ webStateClosingRequested]);
}

// Tests `webState:openURLWithParams:` forwarding.
TEST_F(WebStateDelegateBridgeTest, OpenURLFromWebState) {
  ASSERT_FALSE([delegate_ webState]);
  ASSERT_FALSE([delegate_ openURLParams]);

  web::WebState::OpenURLParams params(
      GURL("https://chromium.test/"), GURL("https://virtual.chromium.test/"),
      web::Referrer(GURL("https://chromium2.test/"), ReferrerPolicyNever),
      WindowOpenDisposition::NEW_WINDOW, ui::PAGE_TRANSITION_FORM_SUBMIT, true);
  EXPECT_EQ(&fake_web_state_,
            bridge_->OpenURLFromWebState(&fake_web_state_, params));

  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
  const web::WebState::OpenURLParams* result_params = [delegate_ openURLParams];
  ASSERT_TRUE(result_params);
  EXPECT_EQ(params.url, result_params->url);
  EXPECT_EQ(params.virtual_url, result_params->virtual_url);
  EXPECT_EQ(params.referrer.url, result_params->referrer.url);
  EXPECT_EQ(params.referrer.policy, result_params->referrer.policy);
  EXPECT_EQ(params.disposition, result_params->disposition);
  EXPECT_EQ(static_cast<int>(params.transition),
            static_cast<int>(result_params->transition));
  EXPECT_EQ(params.is_renderer_initiated, result_params->is_renderer_initiated);
}

// Tests `ShowRepostFormWarningDialog` forwarding.
TEST_F(WebStateDelegateBridgeTest, ShowRepostFormWarningDialog) {
  EXPECT_FALSE([delegate_ repostFormWarningRequested]);
  EXPECT_FALSE([delegate_ webState]);
  base::OnceCallback<void(bool)> callback;
  bridge_->ShowRepostFormWarningDialog(
      &fake_web_state_, web::FormWarningType::kRepost, std::move(callback));
  EXPECT_TRUE([delegate_ repostFormWarningRequested]);
  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
}

// Tests `ShowRepostFormWarningDialog` forwarding to delegate which does not
// implement `webState:runRepostFormDialogWithCompletionHandler:` method.
TEST_F(WebStateDelegateBridgeTest, ShowRepostFormWarningWithNoDelegateMethod) {
  __block bool callback_called = false;
  empty_delegate_bridge_->ShowRepostFormWarningDialog(
      nullptr, web::FormWarningType::kRepost,
      base::BindOnce(^(bool should_repost) {
        EXPECT_TRUE(should_repost);
        callback_called = true;
      }));
  EXPECT_TRUE(callback_called);
}

// Tests `GetJavaScriptDialogPresenter` forwarding.
TEST_F(WebStateDelegateBridgeTest, GetJavaScriptDialogPresenter) {
  EXPECT_FALSE([delegate_ javaScriptDialogPresenterRequested]);
  bridge_->GetJavaScriptDialogPresenter(nullptr);
  EXPECT_TRUE([delegate_ javaScriptDialogPresenterRequested]);
}

// Tests `HandlePermissionsDecisionRequest` forwarding.
TEST_F(WebStateDelegateBridgeTest, HandlePermissionsDecisionRequest) {
  __block bool callback_called = false;
  EXPECT_FALSE([delegate_ permissionsRequestHandled]);
  EXPECT_FALSE([delegate_ webState]);
  bridge_->HandlePermissionsDecisionRequest(
      &fake_web_state_, @[], ^(PermissionDecision decision) {
        EXPECT_EQ(decision, PermissionDecisionGrant);
        callback_called = true;
      });
  EXPECT_TRUE([delegate_ permissionsRequestHandled]);
  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
  EXPECT_TRUE(callback_called);
}

// Tests `HandlePermissionsDecisionRequest` forwarding to delegate which does
// not implement `webState:handlePermissions:decisionHandler:` method.
TEST_F(WebStateDelegateBridgeTest,
       HandlePermissionsDecisionRequestWithNoDelegateMethod) {
  __block bool callback_called = false;
  empty_delegate_bridge_->HandlePermissionsDecisionRequest(
      nullptr, @[], ^(PermissionDecision decision) {
        // Default decision `PermissionDecisionShowDefaultPrompt` will be used
        // when delegate doesn't implement
        // `webState:handlePermissions:decisionHandler:` method to handle the
        // permissions.
        EXPECT_EQ(decision, PermissionDecisionShowDefaultPrompt);
        callback_called = true;
      });
  EXPECT_TRUE(callback_called);
}

// Tests `OnAuthRequired` forwarding.
TEST_F(WebStateDelegateBridgeTest, OnAuthRequired) {
  EXPECT_FALSE([delegate_ authenticationRequested]);
  EXPECT_FALSE([delegate_ webState]);
  NSURLProtectionSpace* protection_space = [[NSURLProtectionSpace alloc] init];
  NSURLCredential* credential = [[NSURLCredential alloc] init];
  WebStateDelegate::AuthCallback callback = base::DoNothing();
  bridge_->OnAuthRequired(&fake_web_state_, protection_space, credential,
                          std::move(callback));
  EXPECT_TRUE([delegate_ authenticationRequested]);
  EXPECT_EQ(&fake_web_state_, [delegate_ webState]);
}

}  // namespace web