blob: a7e5539feffd440d95d858609c2a3d719404cdce [file] [log] [blame]
// 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 "components/omnibox/browser/actions/omnibox_action_in_suggest.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "components/omnibox/browser/actions/omnibox_pedal_provider.h"
#include "components/omnibox/browser/mock_autocomplete_provider_client.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/omnibox_proto/entity_info.pb.h"
#include "third_party/omnibox_proto/suggest_template_info.pb.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
using TemplateAction = omnibox::SuggestTemplateInfo::TemplateAction;
using ActionType = omnibox::SuggestTemplateInfo_TemplateAction_ActionType;
namespace {
class FakeOmniboxAction : public OmniboxAction {
public:
explicit FakeOmniboxAction(OmniboxActionId id)
: OmniboxAction(LabelStrings(u"", u"", u"", u""), GURL{}), id_(id) {}
OmniboxActionId ActionId() const override { return id_; }
private:
~FakeOmniboxAction() override = default;
OmniboxActionId id_{};
};
// Note: can't use operator<<, because ActionType is a plain old enum.
const char* ToString(ActionType type) {
switch (type) {
case omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CALL:
return "Call";
case omnibox::SuggestTemplateInfo_TemplateAction_ActionType_DIRECTIONS:
return "Directions";
case omnibox::SuggestTemplateInfo_TemplateAction_ActionType_REVIEWS:
return "Reviews";
case omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_AIM:
return "Aim";
case omnibox::
SuggestTemplateInfo_TemplateAction_ActionType_CHROME_TAB_SWITCH:
return "TabSwitch";
default:
NOTREACHED();
}
}
} // namespace
class OmniboxActionInSuggestTest : public testing::Test {
public:
OmniboxActionInSuggestTest();
protected:
MockAutocompleteProviderClient client_;
OmniboxAction::ExecutionContext context_;
};
OmniboxActionInSuggestTest::OmniboxActionInSuggestTest()
: context_(client_,
OmniboxAction::ExecutionContext::OpenUrlCallback(),
base::TimeTicks(),
WindowOpenDisposition::IGNORE_ACTION) {}
TEST_F(OmniboxActionInSuggestTest, CheckLabelsArePresentForKnownTypes) {
struct {
ActionType action_type;
int want_hint;
int want_contents;
int want_accessibility_focus_hint;
int want_accessibility_activate_hint;
} test_cases[] = {
{
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CALL,
IDS_OMNIBOX_ACTION_IN_SUGGEST_CALL_HINT,
IDS_OMNIBOX_ACTION_IN_SUGGEST_CALL_CONTENTS,
IDS_ACC_OMNIBOX_ACTION_IN_SUGGEST_SUFFIX,
IDS_OMNIBOX_ACTION_IN_SUGGEST_CALL_CONTENTS,
},
{
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_DIRECTIONS,
IDS_OMNIBOX_ACTION_IN_SUGGEST_DIRECTIONS_HINT,
IDS_OMNIBOX_ACTION_IN_SUGGEST_DIRECTIONS_CONTENTS,
IDS_ACC_OMNIBOX_ACTION_IN_SUGGEST_SUFFIX,
IDS_OMNIBOX_ACTION_IN_SUGGEST_DIRECTIONS_CONTENTS,
},
{
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_REVIEWS,
IDS_OMNIBOX_ACTION_IN_SUGGEST_REVIEWS_HINT,
IDS_OMNIBOX_ACTION_IN_SUGGEST_REVIEWS_CONTENTS,
IDS_ACC_OMNIBOX_ACTION_IN_SUGGEST_SUFFIX,
IDS_OMNIBOX_ACTION_IN_SUGGEST_REVIEWS_CONTENTS,
},
{
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_AIM,
IDS_OMNIBOX_ACTION_IN_SUGGEST_AIM_HINT,
IDS_OMNIBOX_ACTION_IN_SUGGEST_AIM_CONTENTS,
IDS_ACC_OMNIBOX_ACTION_IN_SUGGEST_SUFFIX,
IDS_OMNIBOX_ACTION_IN_SUGGEST_AIM_CONTENTS,
},
{
omnibox::
SuggestTemplateInfo_TemplateAction_ActionType_CHROME_TAB_SWITCH,
IDS_OMNIBOX_ACTION_IN_SUGGEST_TAB_SWITCH_HINT,
IDS_OMNIBOX_ACTION_IN_SUGGEST_TAB_SWITCH_CONTENTS,
IDS_ACC_OMNIBOX_ACTION_IN_SUGGEST_SUFFIX,
IDS_OMNIBOX_ACTION_IN_SUGGEST_TAB_SWITCH_CONTENTS,
}};
for (const auto& test_case : test_cases) {
TemplateAction template_action;
template_action.set_action_type(test_case.action_type);
auto action = base::MakeRefCounted<OmniboxActionInSuggest>(
std::move(template_action), std::nullopt);
EXPECT_EQ(OmniboxActionId::ACTION_IN_SUGGEST, action->ActionId())
<< "while evaluatin action " << ToString(test_case.action_type);
EXPECT_EQ(test_case.action_type, action->Type());
const auto& labels = action->GetLabelStrings();
EXPECT_EQ(labels.hint, l10n_util::GetStringUTF16(test_case.want_hint))
<< "while evaluatin action " << ToString(test_case.action_type);
EXPECT_EQ(labels.suggestion_contents,
l10n_util::GetStringUTF16(test_case.want_contents))
<< "while evaluatin action " << ToString(test_case.action_type);
EXPECT_EQ(
labels.accessibility_suffix,
l10n_util::GetStringUTF16(test_case.want_accessibility_focus_hint))
<< "while evaluatin action " << ToString(test_case.action_type);
EXPECT_EQ(
labels.accessibility_hint,
l10n_util::GetStringUTF16(test_case.want_accessibility_activate_hint))
<< "while evaluatin action " << ToString(test_case.action_type);
}
}
TEST_F(OmniboxActionInSuggestTest, ConversionFromAction) {
const ActionType test_cases[]{
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CALL,
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_DIRECTIONS,
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_REVIEWS,
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_AIM,
omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_TAB_SWITCH};
for (auto test_case : test_cases) {
TemplateAction template_action;
template_action.set_action_type(test_case);
scoped_refptr<OmniboxAction> upcasted_action =
base::MakeRefCounted<OmniboxActionInSuggest>(std::move(template_action),
std::nullopt);
auto* downcasted_action =
OmniboxActionInSuggest::FromAction(upcasted_action.get());
EXPECT_EQ(upcasted_action.get(), downcasted_action)
<< "while evaluatin action " << ToString(test_case);
EXPECT_EQ(test_case, downcasted_action->Type())
<< "while evaluatin action " << ToString(test_case);
}
}
TEST_F(OmniboxActionInSuggestTest, ConversionFromNonAction) {
const OmniboxActionId test_cases[]{OmniboxActionId::HISTORY_CLUSTERS,
OmniboxActionId::PEDAL,
OmniboxActionId::TAB_SWITCH};
for (auto test_case : test_cases) {
auto fake_action = base::MakeRefCounted<FakeOmniboxAction>(test_case);
EXPECT_EQ(nullptr, OmniboxActionInSuggest::FromAction(fake_action.get()));
}
}
TEST_F(OmniboxActionInSuggestTest, AllDeclaredActionTypesAreProperlyReflected) {
// This test verifies that we're not quietly migrating new action types, and
// failing to recognize the need for appropriate coverage, both in terms of
// labels (hints, accessibility) but also UMA metrics.
for (int type = TemplateAction::ActionType_MIN;
type <= TemplateAction::ActionType_MAX; type++) {
if (omnibox::SuggestTemplateInfo_TemplateAction_ActionType_IsValid(type)) {
TemplateAction template_action;
template_action.set_action_type(ActionType(type));
// This is a valid action type. Object MUST build.
auto action = base::MakeRefCounted<OmniboxActionInSuggest>(
std::move(template_action), std::nullopt);
// This is a valid action type. Object MUST be able to report metrics.
{
base::HistogramTester histograms;
action->RecordActionShown(1, false);
// NO actions report to the 'Unknown' bucket.
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Shown", 0, 0);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Used", 0, 0);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Shown", 1);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Used", 0);
}
{
base::HistogramTester histograms;
action->RecordActionShown(1, true);
// NO actions report to the 'Unknown' bucket.
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Shown", 0, 0);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Used", 0, 0);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Shown", 1);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Used", 1);
}
}
}
}
TEST_F(OmniboxActionInSuggestTest, HistogramsRecording) {
enum class UmaTypeForTest {
kUnknown = 0,
kCall,
kDirections,
kWebsite,
kReviews,
kAim,
kLens,
kTabSwitch,
};
// Correlation between ActionType and UMA-recorded bucket.
struct {
omnibox::SuggestTemplateInfo::TemplateAction::ActionType type;
UmaTypeForTest recordedUmaType;
const char* dedicatedHistogram;
} test_cases[]{
{omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CALL,
UmaTypeForTest::kCall, "Omnibox.ActionInSuggest.UsageByType.Call"},
{omnibox::SuggestTemplateInfo_TemplateAction_ActionType_DIRECTIONS,
UmaTypeForTest::kDirections,
"Omnibox.ActionInSuggest.UsageByType.Directions"},
{omnibox::SuggestTemplateInfo_TemplateAction_ActionType_REVIEWS,
UmaTypeForTest::kReviews, "Omnibox.ActionInSuggest.UsageByType.Reviews"},
{omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_AIM,
UmaTypeForTest::kAim, "Omnibox.ActionInSuggest.UsageByType.AIM"},
{omnibox::SuggestTemplateInfo_TemplateAction_ActionType_CHROME_TAB_SWITCH,
UmaTypeForTest::kTabSwitch,
"Omnibox.ActionInSuggest.UsageByType.TabSwitch"},
};
for (const auto& test_case : test_cases) {
TemplateAction template_action;
template_action.set_action_type(test_case.type);
scoped_refptr<OmniboxAction> action =
base::MakeRefCounted<OmniboxActionInSuggest>(std::move(template_action),
std::nullopt);
{
// Just show.
base::HistogramTester histograms;
action->RecordActionShown(1, false);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Shown",
test_case.recordedUmaType, 1);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Used",
test_case.recordedUmaType, 0);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Shown", 1);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Used", 0);
histograms.ExpectBucketCount(test_case.dedicatedHistogram, false, 1);
histograms.ExpectTotalCount(test_case.dedicatedHistogram, 1);
}
{
// Show and execute.
base::HistogramTester histograms;
action->RecordActionShown(1, true);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Shown",
test_case.recordedUmaType, 1);
histograms.ExpectBucketCount("Omnibox.ActionInSuggest.Used",
test_case.recordedUmaType, 1);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Shown", 1);
histograms.ExpectTotalCount("Omnibox.ActionInSuggest.Used", 1);
histograms.ExpectBucketCount(test_case.dedicatedHistogram, true, 1);
histograms.ExpectTotalCount(test_case.dedicatedHistogram, 1);
}
}
}