blob: e84a093bb973b6f8c062b08e8b35b3e61a194977 [file] [log] [blame]
// Copyright 2019 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/on_device_head_model.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/omnibox/browser/omnibox_field_trial.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::ElementsAre;
using testing::Pair;
namespace {
// The test head model used for unittests contains 14 queries and their scores
// shown below; the test model uses 3-bytes address and 2-bytes score so the
// highest score is 32767:
// ----------------------
// Query Score
// ----------------------
// g 32767
// gmail 32766
// google maps 32765
// google 32764
// get out 32763
// googler 32762
// gamestop 32761
// maps 32761
// mail 32760
// map 32759
// 谷歌 32759
// ガツガツしてる人 32759
// 비데 두꺼비 32759
// переводчик 32759
// ----------------------
// The tree structure for queries above is similar as this:
// [ g | ma | 谷歌 | ガツガツしてる人| 비데 두꺼비 | переводчик ]
// | |
// | [ p | il ]
// | |
// | [ # | s ]
// |
// [ # | oogle | mail | et out | amestop ]
// |
// [ # | _maps | er ]
base::FilePath GetTestModelPath() {
base::FilePath file_path;
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &file_path);
file_path = file_path.AppendASCII(
"components/test/data/omnibox/on_device_head_test_model_index.bin");
return file_path;
}
} // namespace
class OnDeviceHeadModelTest : public testing::Test {
protected:
void SetUp() override {
base::FilePath file_path = GetTestModelPath();
ASSERT_TRUE(base::PathExists(file_path));
#if BUILDFLAG(IS_WIN)
model_filename_ = base::WideToUTF8(file_path.value());
#else
model_filename_ = file_path.value();
#endif
ASSERT_FALSE(model_filename_.empty());
}
void TearDown() override { model_filename_.clear(); }
std::string model_filename_;
};
TEST_F(OnDeviceHeadModelTest, GetSuggestions) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "go");
EXPECT_THAT(suggestions,
ElementsAre(Pair("google maps", 32765), Pair("google", 32764),
Pair("googler", 32762)));
suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ge");
EXPECT_THAT(suggestions, ElementsAre(Pair("get out", 32763)));
suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ga");
EXPECT_THAT(suggestions, ElementsAre(Pair("gamestop", 32761)));
}
TEST_F(OnDeviceHeadModelTest, NoMatch) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "x");
EXPECT_TRUE(suggestions.empty());
}
TEST_F(OnDeviceHeadModelTest, MatchTheEndOfSuggestion) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ap");
EXPECT_TRUE(suggestions.empty());
}
TEST_F(OnDeviceHeadModelTest, MatchAtTheMiddleOfSuggestion) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "st");
EXPECT_TRUE(suggestions.empty());
}
TEST_F(OnDeviceHeadModelTest, EmptyInput) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "");
EXPECT_TRUE(suggestions.empty());
}
TEST_F(OnDeviceHeadModelTest, SetMaxSuggestionsToReturn) {
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 5, "g");
EXPECT_THAT(suggestions,
ElementsAre(Pair("g", 32767), Pair("gmail", 32766),
Pair("google maps", 32765), Pair("google", 32764),
Pair("get out", 32763)));
suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 2, "ma");
EXPECT_THAT(suggestions,
ElementsAre(Pair("maps", 32761), Pair("mail", 32760)));
}
TEST_F(OnDeviceHeadModelTest, NonEnglishLanguage) {
// Chinese.
auto suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "谷");
EXPECT_THAT(suggestions, ElementsAre(Pair("谷歌", 32759)));
// Japanese.
suggestions = OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4,
"ガツガツ");
EXPECT_THAT(suggestions, ElementsAre(Pair("ガツガツしてる人", 32759)));
// Korean.
suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "비데 ");
EXPECT_THAT(suggestions, ElementsAre(Pair("비데 두꺼비", 32759)));
// Russian.
suggestions =
OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "пере");
EXPECT_THAT(suggestions, ElementsAre(Pair("переводчик", 32759)));
}
// Test for https://crbug.com/1506547. Similar to
// OnDeviceHeadModelTest.GetSuggestions but search results are collected from
// deeper and wider subtree. Closer to what is done in real model.
TEST(OnDeviceHeadDeepModelTest, SearchSuggestions) {
// Test model contents.
// ----------------------
// Query Score
// ----------------------
// ping 11 1008
// pong 11 1007
// ping 12 1006
// pong 12 1005
// ping 21 1004
// pong 21 1003
// ping 22 1002
// pong 22 1001
base::FilePath file_path;
base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &file_path);
file_path = file_path.AppendASCII(
"components/test/data/omnibox/on_device_head_test_deep_model.bin");
ASSERT_TRUE(base::PathExists(file_path));
std::string model_filename;
#if BUILDFLAG(IS_WIN)
model_filename = base::WideToUTF8(file_path.value());
#else
model_filename = file_path.value();
#endif
std::vector<std::pair<std::string, uint32_t>> reference_suggestions{
{"ping 11", 1008}, {"pong 11", 1007}, {"ping 12", 1006},
{"pong 12", 1005}, {"ping 21", 1004}, {"pong 21", 1003},
{"ping 22", 1002}, {"pong 22", 1001},
};
// Check that for any number of requested matches OnDeviceHeadModel returns
// top entries.
while (!reference_suggestions.empty()) {
auto suggestions = OnDeviceHeadModel::GetSuggestionsForPrefix(
model_filename, reference_suggestions.size(), "p");
EXPECT_EQ(suggestions, reference_suggestions);
reference_suggestions.pop_back();
}
}