chromium/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_unittest.cc

// Copyright 2014 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/ui/views/desktop_capture/desktop_media_picker_views.h"

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "chrome/browser/media/webrtc/desktop_media_picker_controller.h"
#include "chrome/browser/media/webrtc/desktop_media_picker_manager.h"
#include "chrome/browser/media/webrtc/fake_desktop_media_list.h"
#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_controller.h"
#include "chrome/browser/ui/views/desktop_capture/desktop_media_list_view.h"
#include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views_test_api.h"
#include "chrome/browser/ui/views/desktop_capture/desktop_media_source_view.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/views/chrome_test_views_delegate.h"
#include "components/web_modal/test_web_contents_modal_dialog_host.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_utils.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/button/md_text_button.h"
#include "ui/views/controls/tabbed_pane/tabbed_pane.h"
#include "ui/views/test/button_test_api.h"
#include "ui/views/test/scoped_views_test_helper.h"
#include "ui/views/test/test_views_delegate.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/any_widget_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"

#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#endif

DesktopMediaID;

namespace views {

class TestDialogObserver : public DesktopMediaPickerManager::DialogObserver {};

std::vector<DesktopMediaList::Type> GetSourceTypes(bool prefer_current_tab,
                                                   bool new_order) {}

DesktopMediaID::Type GetSourceIdType(DesktopMediaList::Type type) {}

std::string GetTypeAsTestNameString(const DesktopMediaList::Type& type) {}

struct PickerConfiguration {};

namespace {
constexpr std::array<PickerConfiguration, 3> kDefaultProductSourceConfigs =;
}  // namespace

class DesktopMediaPickerViewsTestBase : public testing::Test {};

class DesktopMediaPickerViewsTest
    : public DesktopMediaPickerViewsTestBase,
      public testing::WithParamInterface<PickerConfiguration> {};

INSTANTIATE_TEST_SUITE_P();

TEST_P(DesktopMediaPickerViewsTest, DoneCallbackCalledWhenWindowClosed) {}

TEST_P(DesktopMediaPickerViewsTest, DoneCallbackCalledOnOkButtonPressed) {}

// Regression test for https://crbug.com/1102153
TEST_P(DesktopMediaPickerViewsTest, DoneCallbackNotCalledOnDoubleTap) {}

TEST_P(DesktopMediaPickerViewsTest, CancelButtonAlwaysEnabled) {}

TEST_P(DesktopMediaPickerViewsTest, AudioCheckboxDefaultStates) {}

TEST_P(DesktopMediaPickerViewsTest, DistinctAudioCheckboxesHaveDistinctState) {}

TEST_P(DesktopMediaPickerViewsTest, CurrentTabAndAnyTabShareAudioState) {}

// Verifies the visible status of audio checkbox.
// This test takes it as an article of faith that no checkbox is visible
// when GetAudioShareCheckbox() returns false.
TEST_P(DesktopMediaPickerViewsTest, AudioCheckboxVisibility) {}

// Verifies that audio share information is recorded in the ID if the checkbox
// is checked.
TEST_P(DesktopMediaPickerViewsTest, DoneWithAudioShare) {}

TEST_P(DesktopMediaPickerViewsTest, OkButtonEnabledDuringAcceptSpecific) {}

#if BUILDFLAG(IS_MAC)
TEST_P(DesktopMediaPickerViewsTest, OnPermissionUpdateWithPermissions) {
  if (base::mac::MacOSMajorVersion() < 13) {
    GTEST_SKIP()
        << "ScreenCapturePermissionChecker only created for MacOS 13 and later";
  }

  test_api_.OnPermissionUpdate(true);

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kScreen);
  EXPECT_TRUE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_FALSE(test_api_.GetActivePane()->IsPermissionPaneVisible());

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWindow);
  EXPECT_TRUE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_FALSE(test_api_.GetActivePane()->IsPermissionPaneVisible());

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWebContents);
  EXPECT_TRUE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_FALSE(test_api_.GetActivePane()->IsPermissionPaneVisible());
}

TEST_P(DesktopMediaPickerViewsTest, OnPermissionUpdateWithoutPermissions) {
  if (base::mac::MacOSMajorVersion() < 13) {
    GTEST_SKIP()
        << "ScreenCapturePermissionChecker only created for MacOS 13 and later";
  }

  test_api_.OnPermissionUpdate(false);

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kScreen);
  EXPECT_FALSE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_TRUE(test_api_.GetActivePane()->IsPermissionPaneVisible());

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWindow);
  EXPECT_FALSE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_TRUE(test_api_.GetActivePane()->IsPermissionPaneVisible());

  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWebContents);
  EXPECT_TRUE(test_api_.GetActivePane()->IsContentPaneVisible());
  EXPECT_FALSE(test_api_.GetActivePane()->IsPermissionPaneVisible());
}
#endif

class DesktopMediaPickerViewsPerTypeTest
    : public DesktopMediaPickerViewsTestBase,
      public testing::WithParamInterface<
          std::tuple<PickerConfiguration, DesktopMediaList::Type>> {};

INSTANTIATE_TEST_SUITE_P();

// Verifies that a MediaSourceView is selected with mouse left click and
// original selected MediaSourceView gets unselected.
TEST_P(DesktopMediaPickerViewsPerTypeTest, SelectMediaSourceViewOnSingleClick) {}

// Verifies that the MediaSourceView is added or removed when |media_list_| is
// updated.
TEST_P(DesktopMediaPickerViewsPerTypeTest, AddAndRemoveMediaSource) {}

// Verifies that focusing the MediaSourceView marks it selected and the
// original selected MediaSourceView gets unselected.
TEST_P(DesktopMediaPickerViewsPerTypeTest, FocusMediaSourceViewToSelect) {}

TEST_P(DesktopMediaPickerViewsPerTypeTest, OkButtonDisabledWhenNoSelection) {}

// Verifies that the controller can successfully clear the selection when asked
// to do so.
TEST_P(DesktopMediaPickerViewsPerTypeTest, ClearSelection) {}

class DesktopMediaPickerViewsSystemAudioTest
    : public DesktopMediaPickerViewsTestBase {};

TEST_F(DesktopMediaPickerViewsSystemAudioTest,
       SystemAudioCheckboxVisibleIfExcludeSystemAudioNotSpecified) {}

TEST_F(DesktopMediaPickerViewsSystemAudioTest,
       SystemAudioCheckboxInvisibleIfExcludeSystemAudioSpecified) {}

TEST_F(DesktopMediaPickerViewsSystemAudioTest,
       IfAudioNotRequestedThenExcludeSystemAudioHasNoEffect) {}

// Creates a single pane DesktopMediaPickerViews that only has a tab list.
class DesktopMediaPickerViewsSingleTabPaneTest
    : public DesktopMediaPickerViewsTestBase {};

// Validates that the tab list's preferred size is not zero
// (https://crbug.com/965408).
TEST_F(DesktopMediaPickerViewsSingleTabPaneTest, TabListPreferredSizeNotZero) {}

// Validates that the tab list has a fixed height (https://crbug.com/998485).
TEST_F(DesktopMediaPickerViewsSingleTabPaneTest, TabListHasFixedHeight) {}

// Regression test for https://crbug.com/1042976.
TEST_F(DesktopMediaPickerViewsSingleTabPaneTest,
       CannotAcceptTabWithoutSelection) {}

// Tests accessible properties of DesktopMediaListView and
// DesktopMediaSourceView.
TEST_F(DesktopMediaPickerViewsSingleTabPaneTest, AccessibleProperties) {}

class DesktopMediaPickerPreferredDisplaySurfaceTest
    : public DesktopMediaPickerViewsTestBase,
      public testing::WithParamInterface<
          std::tuple<std::tuple<bool, bool>,
                     blink::mojom::PreferredDisplaySurface>> {};

INSTANTIATE_TEST_SUITE_P();

TEST_P(DesktopMediaPickerPreferredDisplaySurfaceTest,
       SelectedTabMatchesPreferredDisplaySurface) {}

class DesktopMediaPickerDoubleClickTest
    : public DesktopMediaPickerViewsTestBase,
      public testing::WithParamInterface<
          std::pair<DesktopMediaList::Type, DesktopMediaID::Type>> {};

INSTANTIATE_TEST_SUITE_P();

// Regression test for https://crbug.com/1102153 and https://crbug.com/1127496
TEST_P(DesktopMediaPickerDoubleClickTest, DoneCallbackNotCalledOnDoubleClick) {}

// This class expects tests to directly call first SetSourceTypes() and then
// CreatePickerViews().
class DelegatedSourceListTest : public DesktopMediaPickerViewsTestBase {};

// Ensures that Focus/Hide View events get plumbed correctly to the source lists
// upon the view being selected or not.
TEST_F(DelegatedSourceListTest, EnsureFocus) {}

#if BUILDFLAG(IS_MAC)

// Ensures that the first (only) source from a delegated source list is
// selected.
TEST_F(DelegatedSourceListTest, TestSelection) {
  SetSourceTypes(
      {DesktopMediaList::Type::kWebContents},
      {DesktopMediaList::Type::kScreen, DesktopMediaList::Type::kWindow});
  CreatePickerViews(/*request_audio=*/false, /*exclude_system_audio=*/true);

  // Add the one entry that is expected for a delegated source list and switch
  // to it. Note that since this is a delegated source, we must select its pane
  // before the observer will be set for adding items to the list.
  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kScreen);
  media_lists_[DesktopMediaList::Type::kScreen]->AddSourceByFullMediaID(
      DesktopMediaID(GetSourceIdType(DesktopMediaList::Type::kScreen), 10));

  // On MacOS, the added source is automatically selected.
  ASSERT_TRUE(test_api_.GetSelectedSourceId().has_value());
  EXPECT_EQ(10, test_api_.GetSelectedSourceId().value());
}

#else

// Ensures that the first (only) source from a delegated source list is selected
// after being notified that it has made a selection.
TEST_F(DelegatedSourceListTest, TestSelection) {}

#endif  // BUILDFLAG(IS_MACOS)

// Creates a single pane picker and verifies that when it gets notified that the
// delegated source list is dismissed that it finishes without a selection.
TEST_F(DelegatedSourceListTest, SinglePaneReject) {}

// Creates a picker without the default fallback pane and verifies that when it
// gets notified that the delegated source list is dismissed that it finishes
// without a selection.
TEST_F(DelegatedSourceListTest, NoFallbackPaneReject) {}

// Creates a picker with the default fallback pane and verifies that when it
// gets notified that the delegated source list is dismissed that it switches
// to that pane.
TEST_F(DelegatedSourceListTest, SwitchToWebContents) {}

// Creates a picker with the default fallback pane and verifies that when it
// gets notified that the delegated source list is dismissed that it switches
// to that pane and clears any previous selection.
TEST_F(DelegatedSourceListTest, EnsureNoWebContentsSelected) {}

#if BUILDFLAG(IS_MAC)

// The delegated picker experience on MacOS (using SCContentSharingPicker)
// starts the capture immediately after the user has made their choice, so
// the reselect button is not enabled for any capture type
TEST_F(DelegatedSourceListTest, ReselectButtonPresence) {
  SetSourceTypes(
      {DesktopMediaList::Type::kWebContents},
      {DesktopMediaList::Type::kScreen, DesktopMediaList::Type::kWindow});
  CreatePickerViews(/*request_audio=*/false, /*exclude_system_audio=*/true);

  // Ensure that we don't have a reselect button for the non-delegated type.
  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWebContents);
  EXPECT_EQ(nullptr, test_api_.GetReselectButton());

  // Ensure that we don't have a reselect button for the screen delegated type.
  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kScreen);
  ASSERT_EQ(nullptr, test_api_.GetReselectButton());

  // Ensure that we don't have a reselect button for window delegated type.
  test_api_.SelectTabForSourceType(DesktopMediaList::Type::kWindow);
  ASSERT_EQ(nullptr, test_api_.GetReselectButton());
}

#else

// Verify that the reselect button is only present on the delegated source list
// type panes.
TEST_F(DelegatedSourceListTest, ReselectButtonPresence) {}

// Verifies that the reselect button is disabled until a selection has been
// made in the delegated source list, and then disables itself again after a
// click.
TEST_F(DelegatedSourceListTest, ReselectButtonEnabledState) {}

// Verifies that clicking the Reselect button will cause the delegated source
// list to be triggered to show again.
TEST_F(DelegatedSourceListTest, ReselectTriggersShowDelegatedSourceList) {}

#endif  // BUILDFLAG(IS_MAC)
}  // namespace views