chromium/ash/system/nearby_share/nearby_share_feature_pod_controller_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 "ash/system/nearby_share/nearby_share_feature_pod_controller.h"

#include "ash/constants/quick_settings_catalogs.h"
#include "ash/public/cpp/test/test_nearby_share_delegate.h"
#include "ash/shell.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/system/unified/unified_system_tray_bubble.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "ash/test/ash_test_base.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/constants/chromeos_features.h"

namespace ash {

// Tests manually control their session state.
class NearbyShareFeaturePodControllerTest : public NoSessionAshTestBase {
 public:
  NearbyShareFeaturePodControllerTest() = default;
  NearbyShareFeaturePodControllerTest(NearbyShareFeaturePodControllerTest&) =
      delete;
  NearbyShareFeaturePodControllerTest& operator=(
      NearbyShareFeaturePodControllerTest&) = delete;
  ~NearbyShareFeaturePodControllerTest() override = default;

  void SetUp() override {
    NoSessionAshTestBase::SetUp();

    test_delegate_ = static_cast<TestNearbyShareDelegate*>(
        Shell::Get()->nearby_share_delegate());
    nearby_share_controller_ = Shell::Get()->nearby_share_controller();

    test_delegate_->set_is_pod_button_visible(true);

    GetPrimaryUnifiedSystemTray()->ShowBubble();
  }

  void TearDown() override {
    tile_.reset();
    pod_controller_.reset();
    scoped_feature_list_.Reset();
    NoSessionAshTestBase::TearDown();
  }

  bool IsButtonVisible() { return tile_->GetVisible(); }

  bool IsButtonToggled() { return tile_->IsToggled(); }

  void EnableQuickShareV2() {
    scoped_feature_list_.InitWithFeatures(
        /*enabled_features=*/{chromeos::features::kQuickShareV2},
        /*disabled_features=*/{});
  }

 protected:
  void SetUpButton() {
    pod_controller_ =
        std::make_unique<NearbyShareFeaturePodController>(tray_controller());
    tile_ = pod_controller_->CreateTile();
  }

  UnifiedSystemTrayController* tray_controller() {
    return GetPrimaryUnifiedSystemTray()
        ->bubble()
        ->unified_system_tray_controller();
  }

  void PressIcon() { pod_controller_->OnIconPressed(); }

  void PressLabel() { pod_controller_->OnLabelPressed(); }

  void UpdateVisibilityAndNotify(::nearby_share::mojom::Visibility visibility) {
    test_delegate_->set_visibility(visibility);
    nearby_share_controller_->VisibilityChanged(visibility);
  }

  std::unique_ptr<NearbyShareFeaturePodController> pod_controller_;
  std::unique_ptr<FeatureTile> tile_;

  raw_ptr<TestNearbyShareDelegate, DanglingUntriaged> test_delegate_ = nullptr;
  raw_ptr<NearbyShareController, DanglingUntriaged> nearby_share_controller_ =
      nullptr;
  base::test::ScopedFeatureList scoped_feature_list_;
};

TEST_F(NearbyShareFeaturePodControllerTest, ButtonVisibilityNotLoggedIn) {
  SetUpButton();
  // If not logged in, it should not be visible.
  EXPECT_FALSE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonVisibilityLoggedIn) {
  CreateUserSessions(1);
  SetUpButton();
  // If logged in, it should be visible.
  EXPECT_TRUE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonVisibilityLocked) {
  CreateUserSessions(1);
  BlockUserSession(UserSessionBlockReason::BLOCKED_BY_LOCK_SCREEN);

  // Showing the lock screen closes the system tray bubble, so re-show it before
  // setting up the button.
  GetPrimaryUnifiedSystemTray()->ShowBubble();
  SetUpButton();

  // If locked, it should not be visible.
  EXPECT_FALSE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonVisibilityLoginScreen) {
  CreateUserSessions(1);
  BlockUserSession(UserSessionBlockReason::BLOCKED_BY_LOGIN_SCREEN);
  SetUpButton();
  // If the login screen is showing (e.g. multi-user signin), it should not be
  // visible, regardless of whether an active user is signed in.
  EXPECT_FALSE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonVisiblilityHiddenByDelegate) {
  CreateUserSessions(1);
  test_delegate_->set_is_pod_button_visible(false);
  SetUpButton();
  // If NearbyShareDelegate::IsPodButtonVisible() returns false, it should
  // not be visible.
  EXPECT_FALSE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       ButtonToggledByHighVisibilityEnabledEvent) {
  CreateUserSessions(1);
  SetUpButton();
  ASSERT_FALSE(IsButtonToggled());
  nearby_share_controller_->HighVisibilityEnabledChanged(true);
  EXPECT_TRUE(IsButtonToggled());
  nearby_share_controller_->HighVisibilityEnabledChanged(false);
  EXPECT_FALSE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonPressTogglesHighVisibility) {
  CreateUserSessions(1);
  SetUpButton();
  test_delegate_->method_calls().clear();

  test_delegate_->set_is_high_visibility_on(false);
  pod_controller_->OnIconPressed();
  EXPECT_EQ(1u, test_delegate_->method_calls().size());
  EXPECT_EQ(TestNearbyShareDelegate::Method::kEnableHighVisibility,
            test_delegate_->method_calls()[0]);

  test_delegate_->set_is_high_visibility_on(true);
  pod_controller_->OnIconPressed();
  EXPECT_EQ(2u, test_delegate_->method_calls().size());
  EXPECT_EQ(TestNearbyShareDelegate::Method::kDisableHighVisibility,
            test_delegate_->method_calls()[1]);
}

TEST_F(NearbyShareFeaturePodControllerTest, IconUMATracking) {
  CreateUserSessions(1);
  SetUpButton();

  std::string histogram_prefix;
  histogram_prefix = "Ash.QuickSettings.FeaturePod.";

  // No metrics logged before clicking on any views.
  auto histogram_tester = std::make_unique<base::HistogramTester>();
  histogram_tester->ExpectTotalCount(histogram_prefix + "ToggledOn",
                                     /*expected_count=*/0);
  histogram_tester->ExpectTotalCount(histogram_prefix + "ToggledOff",
                                     /*expected_count=*/0);
  histogram_tester->ExpectTotalCount(histogram_prefix + "DiveIn",
                                     /*expected_count=*/0);

  // Toggle on nearby share feature when pressing on the icon.
  PressIcon();
  histogram_tester->ExpectTotalCount(histogram_prefix + "ToggledOn",
                                     /*expected_count=*/1);
  histogram_tester->ExpectTotalCount(histogram_prefix + "ToggledOff",
                                     /*expected_count=*/0);
  histogram_tester->ExpectTotalCount(histogram_prefix + "DiveIn",
                                     /*expected_count=*/0);
  histogram_tester->ExpectBucketCount(histogram_prefix + "ToggledOn",
                                      QsFeatureCatalogName::kNearbyShare,
                                      /*expected_count=*/1);
}

TEST_F(NearbyShareFeaturePodControllerTest, ButtonEnabledStateVisibility) {
  CreateUserSessions(1);
  test_delegate_->set_is_enabled(false);
  SetUpButton();
  // If NearbyShareDelegate::IsEnabled() returns false, the button should
  // not be visible.
  EXPECT_FALSE(IsButtonVisible());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOnYourDevicesVisibility) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  // Default visibility is Your devices.
  SetUpButton();
  EXPECT_TRUE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOnContactsVisibility) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  test_delegate_->set_visibility(
      ::nearby_share::mojom::Visibility::kAllContacts);
  SetUpButton();
  EXPECT_TRUE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOnSelectedContactsVisibility) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  test_delegate_->set_visibility(
      ::nearby_share::mojom::Visibility::kSelectedContacts);
  SetUpButton();
  EXPECT_TRUE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOffHiddenVisibility) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  test_delegate_->set_visibility(::nearby_share::mojom::Visibility::kNoOne);
  SetUpButton();
  EXPECT_FALSE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOn_VisibilityChanged) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  test_delegate_->set_visibility(::nearby_share::mojom::Visibility::kNoOne);
  SetUpButton();
  EXPECT_FALSE(IsButtonToggled());

  UpdateVisibilityAndNotify(::nearby_share::mojom::Visibility::kYourDevices);
  EXPECT_TRUE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOff_VisibilityChanged) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  // Default visibility is Your devices.
  SetUpButton();
  EXPECT_TRUE(IsButtonToggled());

  UpdateVisibilityAndNotify(::nearby_share::mojom::Visibility::kNoOne);
  EXPECT_FALSE(IsButtonToggled());
}

TEST_F(NearbyShareFeaturePodControllerTest,
       QuickShareV2_ButtonToggledOn_HighVisibilityEnabled) {
  EnableQuickShareV2();
  CreateUserSessions(1);
  test_delegate_->set_is_high_visibility_on(true);

  // Setting visibility to kNoOne which alone toggles the button off.
  // If the button is toggled on, it's because high visibility is enabled.
  test_delegate_->set_visibility(::nearby_share::mojom::Visibility::kNoOne);
  SetUpButton();
  EXPECT_TRUE(IsButtonToggled());
}

}  // namespace ash