// 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/personalization_provider.h"
#include <memory>
#include "ash/webui/personalization_app/personalization_app_url_constants.h"
#include "ash/webui/personalization_app/search/search_handler.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/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 "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.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::personalization_app::mojom::SearchResultPtr;
using SearchResult = ::ash::personalization_app::mojom::SearchResult;
using SearchConceptId = ::ash::personalization_app::mojom::SearchConceptId;
SearchResultPtr NewResult(const std::string& url,
const std::u16string& text,
double relevance,
SearchConceptId id) {
SearchResultPtr result = SearchResult::New();
result->search_concept_id = id;
result->relevance_score = relevance;
result->relative_url = url;
result->text = text;
return result;
}
class MockSearchHandler : public ash::personalization_app::SearchHandler {
public:
MockSearchHandler() = default;
~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);
}
std::vector<SearchResultPtr> results_;
};
} // namespace
class PersonalizationProviderTest : public testing::Test {
public:
PersonalizationProviderTest() = default;
PersonalizationProviderTest(const PersonalizationProviderTest&) = delete;
PersonalizationProviderTest& operator=(const PersonalizationProviderTest&) =
delete;
~PersonalizationProviderTest() override = default;
void SetUp() override {
search_controller_ = std::make_unique<TestSearchController>();
profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(profile_manager_->SetUp());
profile_ = profile_manager_->CreateTestingProfile("name");
app_service_proxy_ = apps::AppServiceProxyFactory::GetForProfile(profile_);
apps::StubIconLoader stub_icon_loader;
app_service_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::kPersonalizationAppId] =
1;
mock_handler_ = std::make_unique<MockSearchHandler>();
auto provider = std::make_unique<PersonalizationProvider>(profile_);
provider->MaybeInitialize(mock_handler_.get());
provider_ = provider.get();
search_controller_->AddProvider(std::move(provider));
task_environment_.RunUntilIdle();
}
void TearDown() override {
provider_ = nullptr;
search_controller_.reset();
profile_ = nullptr;
profile_manager_->DeleteTestingProfile("name");
}
const SearchProvider::Results& results() {
return search_controller_->last_results();
}
MockSearchHandler* mock_handler() { return mock_handler_.get(); }
// Starts a search and waits for the query to be sent.
void StartSearch(const std::u16string& query) {
search_controller_->StartSearch(query);
task_environment_.RunUntilIdle();
}
protected:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestSearchController> search_controller_;
std::unique_ptr<MockSearchHandler> mock_handler_;
session_manager::SessionManager session_manager_;
private:
std::unique_ptr<TestingProfileManager> profile_manager_;
raw_ptr<TestingProfile> profile_;
raw_ptr<::apps::AppServiceProxy, DanglingUntriaged> app_service_proxy_;
raw_ptr<PersonalizationProvider> provider_;
};
TEST_F(PersonalizationProviderTest, Basic) {
// Manually add in results from the mocked search handler.
std::vector<SearchResultPtr> personalization_results;
personalization_results.emplace_back(NewResult(
"www.ambient.com", u"Ambient Mode", 0.6, SearchConceptId::kAmbientMode));
personalization_results.emplace_back(
NewResult("www.me.com", u"Personalization", 0.7,
SearchConceptId::kPersonalization));
mock_handler()->SetNextResults(std::move(personalization_results));
// Should not return results if the query is too short.
StartSearch(u"on");
EXPECT_TRUE(results().empty());
StartSearch(u"query");
ASSERT_EQ(2u, results().size());
EXPECT_EQ(results()[0]->title(), u"Ambient Mode");
EXPECT_EQ(results()[0]->id(),
::ash::personalization_app::kChromeUIPersonalizationAppURL +
std::string("www.ambient.com"));
EXPECT_EQ(results()[0]->relevance(), 0.6);
EXPECT_EQ(results()[0]->result_type(), ResultType::kPersonalization);
EXPECT_EQ(results()[0]->category(), Category::kSettings);
EXPECT_EQ(results()[0]->display_type(), DisplayType::kList);
EXPECT_EQ(results()[0]->metrics_type(), ash::PERSONALIZATION);
EXPECT_EQ(results()[0]->icon().dimension, kAppIconDimension);
EXPECT_EQ(results()[1]->title(), u"Personalization");
}
} // namespace app_list::test