chromium/chrome/browser/ash/app_list/search/help_app_provider_unittest.cc

// Copyright 2022 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/ash/app_list/search/help_app_provider.h"

#include <memory>

#include "ash/webui/help_app_ui/search/search_handler.h"
#include "ash/webui/help_app_ui/search/search_tag_registry.h"
#include "ash/webui/help_app_ui/url_constants.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/app_list/app_list_test_util.h"
#include "chrome/browser/ash/app_list/search/chrome_search_result.h"
#include "chrome/browser/ash/app_list/search/common/icon_constants.h"
#include "chrome/browser/ash/app_list/search/test/test_search_controller.h"
#include "chrome/browser/web_applications/web_app_id_constants.h"
#include "components/services/app_service/public/cpp/stub_icon_loader.h"
#include "components/session_manager/core/session_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace app_list::test {

namespace {

using SearchResultPtr = ::ash::help_app::mojom::SearchResultPtr;
using SearchResult = ::ash::help_app::mojom::SearchResult;

SearchResultPtr NewResult(const std::string& url,
                          const std::string& id,
                          const std::u16string& title,
                          double relevance) {
  SearchResultPtr result = SearchResult::New();

  result->id = id;
  result->title = title;
  result->relevance_score = relevance;
  result->url_path_with_parameters = url;
  result->main_category = u"Help";
  result->locale = "us";
  return result;
}

class MockSearchHandler : public ash::help_app::SearchHandler {
 public:
  MockSearchHandler(ash::help_app::SearchTagRegistry* search_tag_registry,
                    ash::local_search_service::LocalSearchServiceProxy*
                        local_search_service_proxy)
      : ash::help_app::SearchHandler(search_tag_registry,
                                     local_search_service_proxy),
        search_tag_registry_(search_tag_registry) {}
  ~MockSearchHandler() override = default;

  MockSearchHandler(const MockSearchHandler& other) = delete;
  MockSearchHandler& operator=(const MockSearchHandler& other) = delete;

  void Search(const std::u16string& query,
              uint32_t max_num_results,
              SearchCallback callback) override {
    std::move(callback).Run(std::move(results_));
  }

  // Manually add in results which will be returned by the Search function.
  void SetNextResults(std::vector<SearchResultPtr> results) {
    results_ = std::move(results);
  }

  raw_ptr<ash::help_app::SearchTagRegistry> search_tag_registry_;
  std::vector<SearchResultPtr> results_;
};
}  // namespace

class HelpAppProviderTest : public AppListTestBase {
 public:
  HelpAppProviderTest()
      : local_search_service_proxy_(
            std::make_unique<
                ash::local_search_service::LocalSearchServiceProxy>(
                /*for_testing=*/true)),
        search_tag_registry_(local_search_service_proxy_.get()),
        mock_handler_(&search_tag_registry_,
                      local_search_service_proxy_.get()) {}
  ~HelpAppProviderTest() override = default;

  void SetUp() override {
    AppListTestBase::SetUp();
    proxy_ = apps::AppServiceProxyFactory::GetForProfile(profile());

    apps::StubIconLoader stub_icon_loader;
    proxy_->OverrideInnerIconLoaderForTesting(&stub_icon_loader);

    // Insert dummy map values so that the stub_icon_loader knows of the app.
    stub_icon_loader.update_version_by_app_id_[web_app::kHelpAppId] = 1;

    auto provider = std::make_unique<HelpAppProvider>(profile());
    provider->MaybeInitialize(&mock_handler_);
    provider_ = provider.get();
    search_controller_.AddProvider(std::move(provider));
  }

  // Starts a search and waits for the query to be sent.
  void StartSearch(const std::u16string& query) {
    search_controller_.StartSearch(query);
    task_environment()->RunUntilIdle();
  }

  const app_list::Results& GetLatestResults() {
    return search_controller_.last_results();
  }

  MockSearchHandler* mock_handler() { return &mock_handler_; }

 private:
  session_manager::SessionManager session_manager_;
  TestSearchController search_controller_;
  std::unique_ptr<ash::local_search_service::LocalSearchServiceProxy>
      local_search_service_proxy_;
  ash::help_app::SearchTagRegistry search_tag_registry_;
  raw_ptr<HelpAppProvider> provider_ = nullptr;
  raw_ptr<apps::AppServiceProxy> proxy_;
  MockSearchHandler mock_handler_;
};

TEST_F(HelpAppProviderTest, Basic) {
  // Manually add in results from the mocked search handler.
  std::vector<SearchResultPtr> search_results;
  search_results.emplace_back(
      NewResult("www.print.com", "test-id-1", u"Printer Help", 0.5));
  search_results.emplace_back(
      NewResult("www.wifi.com", "test-id-2", u"WiFi Help", 0.6));
  mock_handler()->SetNextResults(std::move(search_results));

  // Should not return results if the query is too short.
  StartSearch(u"on");
  EXPECT_TRUE(GetLatestResults().empty());

  StartSearch(u"new");
  ASSERT_EQ(2u, GetLatestResults().size());
  EXPECT_EQ(GetLatestResults()[0]->title(), u"Printer Help");
  EXPECT_EQ(GetLatestResults()[0]->id(),
            ash::kChromeUIHelpAppURL + std::string("www.print.com"));
  EXPECT_EQ(GetLatestResults()[0]->relevance(), 0.5);
  EXPECT_EQ(GetLatestResults()[0]->result_type(), ResultType::kHelpApp);
  EXPECT_EQ(GetLatestResults()[0]->category(), Category::kHelp);
  EXPECT_EQ(GetLatestResults()[0]->display_type(), DisplayType::kList);
  EXPECT_EQ(GetLatestResults()[0]->metrics_type(), ash::HELP_APP_DEFAULT);
  EXPECT_EQ(GetLatestResults()[0]->details(), u"Help");
  EXPECT_EQ(GetLatestResults()[0]->icon().dimension, kAppIconDimension);
}

TEST_F(HelpAppProviderTest, WillFilterResultsBelowTheScoreThreshold) {
  // Manually add in results from the mocked search handler.
  std::vector<SearchResultPtr> search_results;
  search_results.emplace_back(
      NewResult("www.wifiHelp.com", "test-id-4", u"WiFi Helping Hand", 0.7));
  search_results.emplace_back(
      NewResult("www.print.com", "test-id-1", u"Printer Help", 0.3));
  search_results.emplace_back(
      NewResult("www.wifi.com", "test-id-2", u"WiFi Help", 0.6));
  mock_handler()->SetNextResults(std::move(search_results));

  // Should only return the results with a high enough relevance.
  StartSearch(u"query");
  ASSERT_EQ(2u, GetLatestResults().size());
  EXPECT_EQ(GetLatestResults()[0]->title(), u"WiFi Helping Hand");
  EXPECT_EQ(GetLatestResults()[1]->title(), u"WiFi Help");
}

}  // namespace app_list::test