chromium/chrome/browser/external_protocol/external_protocol_handler_unittest.cc

// Copyright 2012 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/external_protocol/external_protocol_handler.h"

#include <memory>
#include <utility>

#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/test_utils.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "components/navigation_interception/intercept_navigation_delegate.h"
#else
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#endif  // BUILDFLAG(IS_ANDROID)

class FakeExternalProtocolHandlerWorker
    : public shell_integration::DefaultSchemeClientWorker {};

class FakeExternalProtocolHandlerDelegate
    : public ExternalProtocolHandler::Delegate {};

class ExternalProtocolHandlerTest : public testing::Test {};

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeNotDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeBlockedChromeUnknown) {}

TEST_F(ExternalProtocolHandlerTest,
       TestLaunchSchemeBlockedChromeOtherModeDefault) {}

// Android doesn't use the external protocol dialog.
#if !BUILDFLAG(IS_ANDROID)

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeNotDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnBlockedChromeUnknown) {}

TEST_F(ExternalProtocolHandlerTest,
       TestLaunchSchemeUnBlockedChromeOtherModeDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeNotDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestLaunchSchemeUnknownChromeUnknown) {}

TEST_F(ExternalProtocolHandlerTest,
       TestLaunchSchemeUnknownChromeOtherModeDefault) {}

TEST_F(ExternalProtocolHandlerTest, TestUrlEscape) {}

TEST_F(ExternalProtocolHandlerTest, TestNoDialogWithoutManager) {}

#else  // if !BUILDFLAG(IS_ANDROID)

class MockInterceptNavigationDelegate
    : public navigation_interception::InterceptNavigationDelegate {
 public:
  MockInterceptNavigationDelegate()
      : InterceptNavigationDelegate(base::android::AttachCurrentThread(),
                                    nullptr) {}

  MOCK_METHOD5(HandleSubframeExternalProtocol,
               void(const GURL&,
                    ui::PageTransition,
                    bool,
                    const std::optional<url::Origin>&,
                    mojo::PendingRemote<network::mojom::URLLoaderFactory>*));
};

TEST_F(ExternalProtocolHandlerTest, TestUrlEscape_Android) {
  GURL url("alert:test message\" --bad%2B\r\n 文本 \"file");
  GURL escaped(
      "alert:test%20message%22%20--bad%2B%20%E6%96%87%E6%9C%AC%20%22file");

  auto delegate = std::make_unique<MockInterceptNavigationDelegate>();

  url::Origin precursor_origin =
      url::Origin::Create(GURL("https://precursor.test"));
  url::Origin opaque_origin =
      url::Origin::Resolve(GURL("data:text/html,hi"), precursor_origin);

  EXPECT_CALL(*delegate.get(),
              HandleSubframeExternalProtocol(testing::Eq(escaped), testing::_,
                                             true, testing::Eq(opaque_origin),
                                             testing::Eq(nullptr)));

  navigation_interception::InterceptNavigationDelegate::Associate(
      web_contents_.get(), std::move(delegate));

  ExternalProtocolHandler::LaunchUrl(
      url,
      base::BindRepeating(&ExternalProtocolHandlerTest::GetWebContents,
                          base::Unretained(this)),
      ui::PAGE_TRANSITION_LINK, /*has_user_gesture=*/true,
      /*is_in_fenced_frame_tree=*/false, opaque_origin,
      content::WeakDocumentPtr(), nullptr);
}

#endif  // if !BUILDFLAG(IS_ANDROID)

TEST_F(ExternalProtocolHandlerTest, TestUrlEscapeNoChecks) {}

TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateUnknown) {}

TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateDefaultBlock) {}

TEST_F(ExternalProtocolHandlerTest, TestGetBlockStateDefaultDontBlock) {}

TEST_F(ExternalProtocolHandlerTest, TestSetBlockState) {}

TEST_F(ExternalProtocolHandlerTest, TestSetBlockStateWithUntrustowrthyOrigin) {}

#if !BUILDFLAG(IS_ANDROID)
// Test that an opaque initiating origin gets transformed to its precursor
// origin when the dialog is shown.
TEST_F(ExternalProtocolHandlerTest, TestOpaqueInitiatingOrigin) {}
#endif