chromium/ash/system/hotspot/hotspot_tray_view_unittest.cc

// Copyright 2023 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/hotspot/hotspot_tray_view.h"

#include "ash/constants/ash_features.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shelf/shelf.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_helper.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/services/hotspot_config/public/cpp/cros_hotspot_config_test_helper.h"
#include "chromeos/ash/services/hotspot_config/public/mojom/cros_hotspot_config.mojom.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/color/color_provider.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/widget/widget.h"

namespace ash {

using hotspot_config::mojom::HotspotInfo;
using hotspot_config::mojom::HotspotState;

namespace {

bool AreImagesEqual(const gfx::ImageSkia& image,
                    const gfx::ImageSkia& reference) {
  return gfx::test::AreBitmapsEqual(*image.bitmap(), *reference.bitmap());
}

}  // namespace

class HotspotTrayViewTest : public AshTestBase {
 public:
  HotspotTrayViewTest()
      : AshTestBase(std::make_unique<base::test::TaskEnvironment>(
            base::test::TaskEnvironment::MainThreadType::UI,
            base::test::TaskEnvironment::TimeSource::MOCK_TIME)) {}
  ~HotspotTrayViewTest() override = default;

  void SetUp() override {
    AshTestBase::SetUp();
    std::unique_ptr<HotspotTrayView> hotspot_tray_view =
        std::make_unique<HotspotTrayView>(GetPrimaryShelf());
    widget_ = CreateFramelessTestWidget();
    widget_->SetFullscreen(true);
    hotspot_tray_view_ = widget_->SetContentsView(std::move(hotspot_tray_view));

    // Spin the runloop to sync up the latest hotspot info.
    base::RunLoop().RunUntilIdle();
  }

  void TearDown() override {
    widget_.reset();
    AshTestBase::TearDown();
  }

  void SetHotspotStateAndClientCount(HotspotState state, size_t client_count) {
    auto hotspot_info = HotspotInfo::New();
    hotspot_info->state = state;
    hotspot_info->client_count = client_count;
    ash_test_helper()->cros_hotspot_config_test_helper()->SetFakeHotspotInfo(
        std::move(hotspot_info));
    base::RunLoop().RunUntilIdle();
  }

  std::u16string GetTooltip() {
    return hotspot_tray_view_->GetTooltipText(gfx::Point());
  }

  std::u16string GetAccessibleNameString() {
    return hotspot_tray_view_->GetAccessibleNameString();
  }

  bool IsIconVisible() { return hotspot_tray_view_->GetVisible(); }

 protected:
  base::test::ScopedFeatureList scoped_feature_list_;
  std::unique_ptr<views::Widget> widget_;
  raw_ptr<HotspotTrayView, DanglingUntriaged> hotspot_tray_view_;
};

TEST_F(HotspotTrayViewTest, HotspotIconImage) {
  SetHotspotStateAndClientCount(HotspotState::kDisabled, 0);
  EXPECT_TRUE(AreImagesEqual(
      hotspot_tray_view_->image_view()->GetImage(),
      gfx::CreateVectorIcon(kHotspotOffIcon, kUnifiedTrayIconSize,
                            widget_->GetColorProvider()->GetColor(
                                cros_tokens::kCrosSysOnSurface))));

  SetHotspotStateAndClientCount(HotspotState::kEnabled, 0);
  EXPECT_TRUE(AreImagesEqual(
      hotspot_tray_view_->image_view()->GetImage(),
      gfx::CreateVectorIcon(kHotspotOnIcon, kUnifiedTrayIconSize,
                            widget_->GetColorProvider()->GetColor(
                                cros_tokens::kCrosSysOnSurface))));

  SetHotspotStateAndClientCount(HotspotState::kEnabling, 0);
  EXPECT_TRUE(AreImagesEqual(
      hotspot_tray_view_->image_view()->GetImage(),
      gfx::CreateVectorIcon(kHotspotDotIcon, kUnifiedTrayIconSize,
                            widget_->GetColorProvider()->GetColor(
                                cros_tokens::kCrosSysOnSurface))));
  // Verifies the hotspot icon is animating when enabling.
  task_environment()->FastForwardBy(base::Milliseconds(500));
  EXPECT_TRUE(AreImagesEqual(
      hotspot_tray_view_->image_view()->GetImage(),
      gfx::CreateVectorIcon(kHotspotOneArcIcon, kUnifiedTrayIconSize,
                            widget_->GetColorProvider()->GetColor(
                                cros_tokens::kCrosSysOnSurface))));
  task_environment()->FastForwardBy(base::Milliseconds(500));
  EXPECT_TRUE(AreImagesEqual(
      hotspot_tray_view_->image_view()->GetImage(),
      gfx::CreateVectorIcon(kHotspotOnIcon, kUnifiedTrayIconSize,
                            widget_->GetColorProvider()->GetColor(
                                cros_tokens::kCrosSysOnSurface))));
}

TEST_F(HotspotTrayViewTest, HotspotIconVisibility) {
  EXPECT_FALSE(IsIconVisible());

  SetHotspotStateAndClientCount(HotspotState::kEnabled, 0);
  EXPECT_TRUE(IsIconVisible());

  SetHotspotStateAndClientCount(HotspotState::kDisabled, 0);
  EXPECT_FALSE(IsIconVisible());

  SetHotspotStateAndClientCount(HotspotState::kEnabling, 0);
  EXPECT_TRUE(IsIconVisible());
}

TEST_F(HotspotTrayViewTest, HotspotIconTooltip) {
  SetHotspotStateAndClientCount(HotspotState::kEnabled, 0);
  EXPECT_EQ(l10n_util::GetStringFUTF16(
                IDS_ASH_STATUS_TRAY_HOTSPOT_ON_NO_CONNECTED_DEVICES,
                ui::GetChromeOSDeviceName()),
            GetTooltip());
  EXPECT_EQ(GetTooltip(), GetAccessibleNameString());

  SetHotspotStateAndClientCount(HotspotState::kEnabled, 1);
  EXPECT_EQ(l10n_util::GetStringFUTF16(
                IDS_ASH_STATUS_TRAY_HOTSPOT_ON_ONE_CONNECTED_DEVICE,
                ui::GetChromeOSDeviceName()),
            GetTooltip());
  EXPECT_EQ(GetTooltip(), GetAccessibleNameString());

  SetHotspotStateAndClientCount(HotspotState::kEnabled, 3);
  EXPECT_EQ(l10n_util::GetStringFUTF16(
                IDS_ASH_STATUS_TRAY_HOTSPOT_ON_MULTIPLE_CONNECTED_DEVICES,
                base::NumberToString16(3), ui::GetChromeOSDeviceName()),
            GetTooltip());
  EXPECT_EQ(GetTooltip(), GetAccessibleNameString());
}

TEST_F(HotspotTrayViewTest, AccessibleProperties) {
  ui::AXNodeData data;

  hotspot_tray_view_->GetViewAccessibility().GetAccessibleNodeData(&data);
  EXPECT_EQ(data.role, ax::mojom::Role::kImage);
}

}  // namespace ash