chromium/content/browser/web_contents/color_chooser_unittest.cc

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

#include "content/public/browser/color_chooser.h"

#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/content_navigation_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_features.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/navigation_simulator.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_render_view_host.h"
#include "content/test/test_web_contents.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace content {

namespace {

// Mock content::ColorChooser to test whether End() is called.
class MockColorChooser : public content::ColorChooser {
 public:
  MockColorChooser() = default;

  MockColorChooser(const MockColorChooser&) = delete;
  MockColorChooser& operator=(const MockColorChooser&) = delete;

  ~MockColorChooser() override = default;

  MOCK_METHOD0(End, void());
  MOCK_METHOD1(SetSelectedColor, void(SkColor color));
};

// Delegate to override OpenColorChooser.
class OpenColorChooserDelegate : public WebContentsDelegate {
 public:
  explicit OpenColorChooserDelegate(
      std::unique_ptr<MockColorChooser> mock_color_chooser)
      : mock_color_chooser_(std::move(mock_color_chooser)) {}

  OpenColorChooserDelegate(const OpenColorChooserDelegate&) = delete;
  OpenColorChooserDelegate& operator=(const OpenColorChooserDelegate&) = delete;

  ~OpenColorChooserDelegate() override = default;

  // WebContentsDelegate:
  std::unique_ptr<ColorChooser> OpenColorChooser(
      WebContents* web_contents,
      SkColor color,
      const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions)
      override {
    return std::move(mock_color_chooser_);
  }

  bool IsBackForwardCacheSupported(WebContents& web_contents) override {
    return true;
  }

 private:
  std::unique_ptr<MockColorChooser> mock_color_chooser_;
};

}  // namespace

class ColorChooserUnitTest : public RenderViewHostImplTestHarness {};

#if BUILDFLAG(IS_ANDROID)
// The ColorChooser is only available/called on Android.
TEST_F(ColorChooserUnitTest, ColorChooserCallsEndOnNavigatingAway) {
  GURL kUrl1("https://foo.com");
  GURL kUrl2("https://bar.com");

  // End should be called at least once on navigating to a new URL.
  std::unique_ptr<MockColorChooser> mock_color_chooser =
      std::make_unique<MockColorChooser>();
  EXPECT_CALL(*mock_color_chooser.get(), End()).Times(testing::AtLeast(1));

  // Set OpenColorChooserDelegate as the new WebContentsDelegate.
  std::unique_ptr<OpenColorChooserDelegate> delegate =
      std::make_unique<OpenColorChooserDelegate>(std::move(mock_color_chooser));
  contents()->SetDelegate(delegate.get());

  // Navigate to A.
  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl1);

  mojo::PendingRemote<blink::mojom::ColorChooserClient> pending_client;
  mojo::Remote<blink::mojom::ColorChooser> pending_remote;
  mojo::PendingReceiver<blink::mojom::ColorChooser> pending_receiver =
      pending_remote.BindNewPipeAndPassReceiver();

  // Call WebContentsImpl::OpenColorChooser.
  static_cast<WebContentsImpl*>(contents())
      ->OpenColorChooser(std::move(pending_receiver), std::move(pending_client),
                         SkColorSetRGB(0, 0, 1), {});

  // Navigate to B.
  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl2);

  contents()->SetDelegate(nullptr);
}
#endif

// Run tests with BackForwardCache.
class ColorChooserTestWithBackForwardCache : public ColorChooserUnitTest {
 public:
  ColorChooserTestWithBackForwardCache() {
    scoped_feature_list_.InitWithFeaturesAndParameters(
        GetDefaultEnabledBackForwardCacheFeaturesForTesting(
            /*ignore_outstanding_network_request=*/false),
        GetDefaultDisabledBackForwardCacheFeaturesForTesting());
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};

#if BUILDFLAG(IS_ANDROID)
// The ColorChooser is only available/called on Android.
TEST_F(ColorChooserTestWithBackForwardCache,
       ColorChooserCallsEndOnEnteringBackForwardCache) {
  ASSERT_TRUE(IsBackForwardCacheEnabled());
  GURL kUrl1("https://foo.com");
  GURL kUrl2("https://bar.com");

  // End should be called at least once on navigating to a new URL.
  std::unique_ptr<MockColorChooser> mock_color_chooser =
      std::make_unique<MockColorChooser>();
  EXPECT_CALL(*mock_color_chooser.get(), End()).Times(testing::AtLeast(1));

  // Set OpenColorChooserDelegate as the new WebContentsDelegate.
  std::unique_ptr<OpenColorChooserDelegate> delegate =
      std::make_unique<OpenColorChooserDelegate>(std::move(mock_color_chooser));
  contents()->SetDelegate(delegate.get());

  // Navigate to A.
  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl1);
  RenderFrameHostImpl* rfh_a = contents()->GetPrimaryMainFrame();

  mojo::PendingRemote<blink::mojom::ColorChooserClient> pending_client;
  mojo::Remote<blink::mojom::ColorChooser> pending_remote;
  mojo::PendingReceiver<blink::mojom::ColorChooser> pending_receiver =
      pending_remote.BindNewPipeAndPassReceiver();

  // Call WebContentsImpl::OpenColorChooser.
  static_cast<WebContentsImpl*>(contents())
      ->OpenColorChooser(std::move(pending_receiver), std::move(pending_client),
                         SkColorSetRGB(0, 0, 1), {});

  // Navigate to B, A enters BackForwardCache.
  NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl2);
  EXPECT_TRUE(rfh_a->IsInBackForwardCache());

  contents()->SetDelegate(nullptr);
}
#endif

}  // namespace content