blob: ff54668bc5d81cb8ea6e8d22708b912adb1e0b7c [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/omnibox/browser/featured_search_provider.h"
#include <stddef.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/mock_autocomplete_provider_client.h"
#include "components/omnibox/browser/test_scheme_classifier.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_service.h"
#include "components/search_engines/template_url_starter_pack_data.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/omnibox_event.pb.h"
#include "third_party/metrics_proto/omnibox_focus_type.pb.h"
#include "url/gurl.h"
class FeaturedSearchProviderTest : public testing::Test {
protected:
struct TestData {
const std::u16string input;
const std::vector<GURL> output;
};
FeaturedSearchProviderTest() : provider_(nullptr) {}
~FeaturedSearchProviderTest() override {}
FeaturedSearchProviderTest(const FeaturedSearchProviderTest&) = delete;
FeaturedSearchProviderTest& operator=(const FeaturedSearchProviderTest&) =
delete;
void SetUp() override {
client_ = std::make_unique<MockAutocompleteProviderClient>();
client_->set_template_url_service(
std::make_unique<TemplateURLService>(nullptr, 0));
provider_ = new FeaturedSearchProvider(client_.get());
}
void TearDown() override { provider_ = nullptr; }
void RunTest(const TestData cases[], size_t num_cases) {
ACMatches matches;
for (size_t i = 0; i < num_cases; ++i) {
SCOPED_TRACE(base::StringPrintf(
"case %" PRIuS ": %s", i, base::UTF16ToUTF8(cases[i].input).c_str()));
AutocompleteInput input(cases[i].input, metrics::OmniboxEventProto::OTHER,
TestSchemeClassifier());
input.set_prevent_inline_autocomplete(true);
provider_->Start(input, false);
EXPECT_TRUE(provider_->done());
matches = provider_->matches();
ASSERT_EQ(cases[i].output.size(), matches.size());
for (size_t j = 0; j < cases[i].output.size(); ++j) {
EXPECT_EQ(cases[i].output[j], matches[j].destination_url);
}
}
}
std::unique_ptr<MockAutocompleteProviderClient> client_;
scoped_refptr<FeaturedSearchProvider> provider_;
};
TEST_F(FeaturedSearchProviderTest, NonAtPrefix) {
TestData test_cases[] = {
// Typing text that doesn't start with "@" should give nothing.
{u"g@rb@g3", {}},
{u"www.google.com", {}},
{u"http:www.google.com", {}},
{u"http://www.google.com", {}},
{u"file:filename", {}},
{u"chrome:", {}},
{u"chrome://", {}},
{u"chrome://version", {}},
};
RunTest(test_cases, std::size(test_cases));
}
TEST_F(FeaturedSearchProviderTest, DoesNotSupportMatchesOnFocus) {
AutocompleteInput input(u"@tabs", metrics::OmniboxEventProto::OTHER,
TestSchemeClassifier());
input.set_focus_type(metrics::OmniboxFocusType::INTERACTION_FOCUS);
provider_->Start(input, false);
EXPECT_TRUE(provider_->matches().empty());
}
TEST_F(FeaturedSearchProviderTest, StarterPack) {
base::test::ScopedFeatureList features;
features.InitAndDisableFeature(omnibox::kStarterPackExpansion);
const GURL kBookmarksUrl =
GURL(TemplateURLStarterPackData::bookmarks.destination_url);
const GURL kHistoryUrl =
GURL(TemplateURLStarterPackData::history.destination_url);
const GURL kTabsUrl = GURL(TemplateURLStarterPackData::tabs.destination_url);
const std::u16string kBookmarksKeyword = u"@bookmarks";
const std::u16string kHistoryKeyword = u"@history";
const std::u16string kTabsKeyword = u"@tabs";
// Populate template URL with starter pack entries
std::vector<std::unique_ptr<TemplateURLData>> turls =
TemplateURLStarterPackData::GetStarterPackEngines();
for (auto& turl : turls) {
client_->GetTemplateURLService()->Add(
std::make_unique<TemplateURL>(std::move(*turl)));
}
TestData typing_scheme_cases[] = {
// Typing the keyword without '@' or past the keyword shouldn't produce
// results.
{u"b", {}},
{u"bookmarks", {}},
{u"his", {}},
{u"history", {}},
{u"@historyasdjflk", {}},
{u"@bookmarksasld", {}},
{u"tabs", {}},
// With the expansion flag disabled, typing the `@gemini` keyword should
// not provide the Gemini suggestion.
{u"@gemini", {}},
// Typing '@' should give all the starter pack suggestions.
{u"@", {kBookmarksUrl, kHistoryUrl, kTabsUrl}},
// Typing a portion of "@bookmarks" should give the bookmarks suggestion.
{kBookmarksKeyword.substr(0, 3), {kBookmarksUrl}},
{kBookmarksKeyword, {kBookmarksUrl}},
// Typing a portion of "@history" should give the default urls.
{kHistoryKeyword.substr(0, 3), {kHistoryUrl}},
{kHistoryKeyword, {kHistoryUrl}},
// Typing a portion of "@tabs" should give the default urls.
{kTabsKeyword.substr(0, 3), {kTabsUrl}},
{kTabsKeyword, {kTabsUrl}},
};
RunTest(typing_scheme_cases, std::size(typing_scheme_cases));
}
TEST_F(FeaturedSearchProviderTest, StarterPackExpansion) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(omnibox::kStarterPackExpansion);
const GURL kBookmarksUrl =
GURL(TemplateURLStarterPackData::bookmarks.destination_url);
const GURL kHistoryUrl =
GURL(TemplateURLStarterPackData::history.destination_url);
const GURL kTabsUrl = GURL(TemplateURLStarterPackData::tabs.destination_url);
const GURL kAskGoogleUrl =
GURL(TemplateURLStarterPackData::AskGoogle.destination_url);
const std::u16string kBookmarksKeyword = u"@bookmarks";
const std::u16string kHistoryKeyword = u"@history";
const std::u16string kTabsKeyword = u"@tabs";
const std::u16string kAskGoogleKeyword = u"@gemini";
// Populate template URL with starter pack entries
std::vector<std::unique_ptr<TemplateURLData>> turls =
TemplateURLStarterPackData::GetStarterPackEngines();
for (auto& turl : turls) {
client_->GetTemplateURLService()->Add(
std::make_unique<TemplateURL>(std::move(*turl)));
}
TestData typing_scheme_cases[] = {
// Typing the keyword without '@' or past the keyword shouldn't produce
// results.
{u"b", {}},
{u"bookmarks", {}},
{u"his", {}},
{u"history", {}},
{u"@historyasdjflk", {}},
{u"@bookmarksasld", {}},
{u"tabs", {}},
{u"gemi", {}},
// Typing '@' should give all the starter pack suggestions.
{u"@", {kBookmarksUrl, kAskGoogleUrl, kHistoryUrl, kTabsUrl}},
// Typing a portion of "@bookmarks" should give the bookmarks suggestion.
{kBookmarksKeyword.substr(0, 3), {kBookmarksUrl}},
{kBookmarksKeyword, {kBookmarksUrl}},
// Typing a portion of "@history" should give the default urls.
{kHistoryKeyword.substr(0, 3), {kHistoryUrl}},
{kHistoryKeyword, {kHistoryUrl}},
// Typing a portion of "@tabs" should give the default urls.
{kTabsKeyword.substr(0, 3), {kTabsUrl}},
{kTabsKeyword, {kTabsUrl}},
// Typing a portion of "@gemini" should give the default urls.
{kAskGoogleKeyword.substr(0, 3), {kAskGoogleUrl}},
{kAskGoogleKeyword, {kAskGoogleUrl}},
};
RunTest(typing_scheme_cases, std::size(typing_scheme_cases));
}
TEST_F(FeaturedSearchProviderTest, StarterPackExpansionRelevance) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(omnibox::kStarterPackExpansion);
const GURL kBookmarksUrl =
GURL(TemplateURLStarterPackData::bookmarks.destination_url);
const GURL kHistoryUrl =
GURL(TemplateURLStarterPackData::history.destination_url);
const GURL kTabsUrl = GURL(TemplateURLStarterPackData::tabs.destination_url);
const GURL kAskGoogleUrl =
GURL(TemplateURLStarterPackData::AskGoogle.destination_url);
// Populate template URL with starter pack entries
std::vector<std::unique_ptr<TemplateURLData>> turls =
TemplateURLStarterPackData::GetStarterPackEngines();
for (auto& turl : turls) {
client_->GetTemplateURLService()->Add(
std::make_unique<TemplateURL>(std::move(*turl)));
}
AutocompleteInput input(u"@", metrics::OmniboxEventProto::OTHER,
TestSchemeClassifier());
input.set_prevent_inline_autocomplete(true);
provider_->Start(input, false);
EXPECT_TRUE(provider_->done());
ACMatches matches = provider_->matches();
ASSERT_EQ(turls.size(), matches.size());
// Sort the matches according to relevances (in descending order), and make
// sure that the matches are in the expected order.
std::sort(matches.begin(), matches.end(), [](const auto& x, const auto& y) {
return x.relevance > y.relevance;
});
GURL expected_match_order[] = {kAskGoogleUrl, kBookmarksUrl, kHistoryUrl,
kTabsUrl};
for (size_t i = 0; i < matches.size(); i++) {
EXPECT_EQ(matches[i].destination_url, expected_match_order[i]);
}
}