chromium/ash/webui/shortcut_customization_ui/shortcuts_app_manager_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/webui/shortcut_customization_ui/shortcuts_app_manager.h"

#include <cstdint>
#include <memory>
#include <vector>

#include "ash/constants/ash_features.h"
#include "ash/public/cpp/accelerator_configuration.h"
#include "ash/public/mojom/accelerator_info.mojom-shared.h"
#include "ash/public/mojom/accelerator_info.mojom.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/webui/shortcut_customization_ui/backend/accelerator_configuration_provider.h"
#include "ash/webui/shortcut_customization_ui/backend/search/fake_search_data.h"
#include "ash/webui/shortcut_customization_ui/backend/search/search_concept_registry.h"
#include "ash/webui/shortcut_customization_ui/shortcuts_app_manager.h"
#include "base/containers/flat_map.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/ash/components/local_search_service/public/cpp/local_search_service_proxy.h"
#include "chromeos/ash/components/test/ash_test_suite.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"

namespace ash::shortcut_ui {

class ShortcutsAppManagerTest : public AshTestBase {
 protected:
  ShortcutsAppManagerTest() = default;
  ~ShortcutsAppManagerTest() override = default;

  // AshTestBase:
  void SetUp() override {
    ui::ResourceBundle::CleanupSharedInstance();
    AshTestSuite::LoadTestResources();
    AshTestBase::SetUp();

    local_search_service_proxy_ =
        std::make_unique<local_search_service::LocalSearchServiceProxy>(
            /*for_testing=*/true);

    manager_ = std::make_unique<ShortcutsAppManager>(
        local_search_service_proxy_.get(),
        Shell::Get()->session_controller()->GetActivePrefService());

    // Let the RunLoop so that the AshAcceleratorConfiguration can load its
    // default accelerators.
    base::RunLoop().RunUntilIdle();
  }

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

  void ValidateSearchConceptById(
      const base::flat_map<std::string, SearchConcept>& search_concepts_map,
      const std::string search_concept_id,
      const mojom::AcceleratorSource expected_source,
      const uint32_t expected_action) const {
    EXPECT_TRUE(search_concepts_map.contains(search_concept_id));
    EXPECT_EQ(search_concepts_map.at(search_concept_id)
                  .accelerator_layout_info->source,
              expected_source);
    EXPECT_EQ(search_concepts_map.at(search_concept_id)
                  .accelerator_layout_info->action,
              expected_action);
  }

  base::test::ScopedFeatureList scoped_feature_list_;
  std::unique_ptr<local_search_service::LocalSearchServiceProxy>
      local_search_service_proxy_;
  std::unique_ptr<ShortcutsAppManager> manager_;
};

TEST_F(ShortcutsAppManagerTest, SetSearchConcepts) {
  // Create all the fake AcceleratorInfo maps for use in the fake config.
  AcceleratorConfigurationProvider::ActionIdToAcceleratorsInfoMap ash_info_map;
  ash_info_map.insert({fake_search_data::FakeActionIds::kAction1,
                       fake_search_data::CreateFakeAcceleratorInfoList()});
  ash_info_map.insert({fake_search_data::FakeActionIds::kAction2,
                       fake_search_data::CreateFakeAcceleratorInfoList(
                           ash::mojom::AcceleratorState::kDisabledByUser)});

  AcceleratorConfigurationProvider::ActionIdToAcceleratorsInfoMap
      browser_info_map;
  browser_info_map.insert({fake_search_data::FakeActionIds::kAction3,
                           fake_search_data::CreateFakeAcceleratorInfoList()});
  browser_info_map.insert({fake_search_data::FakeActionIds::kAction4,
                           fake_search_data::CreateFakeAcceleratorInfoList()});

  // Create the fake config.
  shortcut_ui::AcceleratorConfigurationProvider::AcceleratorConfigurationMap
      fake_config;
  fake_config.insert({mojom::AcceleratorSource::kAsh, std::move(ash_info_map)});
  fake_config.insert(
      {mojom::AcceleratorSource::kBrowser, std::move(browser_info_map)});

  // Create the fake AcceleratorLayoutInfos list.
  std::vector<mojom::AcceleratorLayoutInfoPtr> fake_layout_infos;
  fake_layout_infos.push_back(fake_search_data::CreateFakeAcceleratorLayoutInfo(
      u"Open launcher", ash::mojom::AcceleratorSource::kAsh,
      fake_search_data::FakeActionIds::kAction1,
      ash::mojom::AcceleratorLayoutStyle::kDefault));
  fake_layout_infos.push_back(fake_search_data::CreateFakeAcceleratorLayoutInfo(
      u"Open/close calendar", ash::mojom::AcceleratorSource::kAsh,
      fake_search_data::FakeActionIds::kAction2,
      ash::mojom::AcceleratorLayoutStyle::kDefault));
  fake_layout_infos.push_back(fake_search_data::CreateFakeAcceleratorLayoutInfo(
      u"Open new tab", ash::mojom::AcceleratorSource::kBrowser,
      fake_search_data::FakeActionIds::kAction3,
      ash::mojom::AcceleratorLayoutStyle::kDefault));
  fake_layout_infos.push_back(fake_search_data::CreateFakeAcceleratorLayoutInfo(
      u"Close tab", ash::mojom::AcceleratorSource::kBrowser,
      fake_search_data::FakeActionIds::kAction4,
      ash::mojom::AcceleratorLayoutStyle::kDefault));

  auto& registry_search_concepts =
      manager_->search_concept_registry_.get()->result_id_to_search_concept_;

  // AshAcceleratorConfiguration loads some initial accelerators (which ends up
  // populating the registry map), so clear the registry map to get a fresh
  // slate for the test.
  registry_search_concepts.clear();
  EXPECT_EQ(registry_search_concepts.size(), 0u);

  manager_->SetSearchConcepts(std::move(fake_config),
                              std::move(fake_layout_infos));
  base::RunLoop().RunUntilIdle();

  // Disabled accelerator info is included, which will be displayed as 'No
  // shortcut assigned' in the frontend.
  EXPECT_EQ(registry_search_concepts.size(), 4u);

  // Test that the expected search concepts are present and check a few
  // attributes to be sure.
  ValidateSearchConceptById(/*search_concepts_map=*/registry_search_concepts,
                            /*search_concept_id=*/"0-1",
                            /*expected_source=*/mojom::AcceleratorSource::kAsh,
                            /*expected_action=*/fake_search_data::kAction1);
  ValidateSearchConceptById(
      /*search_concepts_map=*/registry_search_concepts,
      /*search_concept_id=*/"0-2",
      /*expected_source=*/mojom::AcceleratorSource::kAsh,
      /*expected_action=*/fake_search_data::kAction2);
  ValidateSearchConceptById(
      /*search_concepts_map=*/registry_search_concepts,
      /*search_concept_id=*/"2-3",
      /*expected_source=*/mojom::AcceleratorSource::kBrowser,
      /*expected_action=*/fake_search_data::kAction3);
  ValidateSearchConceptById(
      /*search_concepts_map=*/registry_search_concepts,
      /*search_concept_id=*/"2-4",
      /*expected_source=*/mojom::AcceleratorSource::kBrowser,
      /*expected_action=*/fake_search_data::kAction4);
}

}  // namespace ash::shortcut_ui