1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/omnibox/browser/on_device_head_model.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/path_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "build/build_config.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 using testing::ElementsAre;
16 using testing::Pair;
17 
18 namespace {
19 
20 // The test head model used for unittests contains 14 queries and their scores
21 // shown below; the test model uses 3-bytes address and 2-bytes score so the
22 // highest score is 32767:
23 // ----------------------
24 // Query            Score
25 // ----------------------
26 // g                32767
27 // gmail            32766
28 // google maps      32765
29 // google           32764
30 // get out          32763
31 // googler          32762
32 // gamestop         32761
33 // maps             32761
34 // mail             32760
35 // map              32759
36 // 谷歌              32759
37 // ガツガツしてる人    32759
38 // 비데 두꺼비         32759
39 // переводчик       32759
40 // ----------------------
41 // The tree structure for queries above is similar as this:
42 //  [ g | ma | 谷歌 | ガツガツしてる人| 비데 두꺼비 | переводчик ]
43 //    |   |
44 //    | [ p | il ]
45 //    |   |
46 //    | [ # | s ]
47 //    |
48 //  [ # | oogle | mail | et out | amestop ]
49 //          |
50 //        [ # | _maps | er ]
51 
GetTestModelPath()52 base::FilePath GetTestModelPath() {
53   base::FilePath file_path;
54   base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
55   file_path = file_path.AppendASCII(
56       "components/test/data/omnibox/on_device_head_test_model_index.bin");
57   return file_path;
58 }
59 
60 }  // namespace
61 
62 class OnDeviceHeadModelTest : public testing::Test {
63  protected:
SetUp()64   void SetUp() override {
65     base::FilePath file_path = GetTestModelPath();
66     ASSERT_TRUE(base::PathExists(file_path));
67 #if defined(OS_WIN)
68     model_filename_ = base::WideToUTF8(file_path.value());
69 #else
70     model_filename_ = file_path.value();
71 #endif
72     ASSERT_FALSE(model_filename_.empty());
73   }
74 
TearDown()75   void TearDown() override { model_filename_.clear(); }
76 
77   std::string model_filename_;
78 };
79 
TEST_F(OnDeviceHeadModelTest,GetSuggestions)80 TEST_F(OnDeviceHeadModelTest, GetSuggestions) {
81   auto suggestions =
82       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "go");
83   EXPECT_THAT(suggestions,
84               ElementsAre(Pair("google maps", 32765), Pair("google", 32764),
85                           Pair("googler", 32762)));
86 
87   suggestions =
88       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ge");
89   EXPECT_THAT(suggestions, ElementsAre(Pair("get out", 32763)));
90 
91   suggestions =
92       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ga");
93   EXPECT_THAT(suggestions, ElementsAre(Pair("gamestop", 32761)));
94 }
95 
TEST_F(OnDeviceHeadModelTest,NoMatch)96 TEST_F(OnDeviceHeadModelTest, NoMatch) {
97   auto suggestions =
98       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "x");
99   EXPECT_TRUE(suggestions.empty());
100 }
101 
TEST_F(OnDeviceHeadModelTest,MatchTheEndOfSuggestion)102 TEST_F(OnDeviceHeadModelTest, MatchTheEndOfSuggestion) {
103   auto suggestions =
104       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "ap");
105   EXPECT_TRUE(suggestions.empty());
106 }
107 
TEST_F(OnDeviceHeadModelTest,MatchAtTheMiddleOfSuggestion)108 TEST_F(OnDeviceHeadModelTest, MatchAtTheMiddleOfSuggestion) {
109   auto suggestions =
110       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "st");
111   EXPECT_TRUE(suggestions.empty());
112 }
113 
TEST_F(OnDeviceHeadModelTest,EmptyInput)114 TEST_F(OnDeviceHeadModelTest, EmptyInput) {
115   auto suggestions =
116       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "");
117   EXPECT_TRUE(suggestions.empty());
118 }
119 
TEST_F(OnDeviceHeadModelTest,SetMaxSuggestionsToReturn)120 TEST_F(OnDeviceHeadModelTest, SetMaxSuggestionsToReturn) {
121   auto suggestions =
122       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 5, "g");
123   EXPECT_THAT(suggestions,
124               ElementsAre(Pair("g", 32767), Pair("gmail", 32766),
125                           Pair("google maps", 32765), Pair("google", 32764),
126                           Pair("get out", 32763)));
127 
128   suggestions =
129       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 2, "ma");
130   EXPECT_THAT(suggestions,
131               ElementsAre(Pair("maps", 32761), Pair("mail", 32760)));
132 }
133 
TEST_F(OnDeviceHeadModelTest,NonEnglishLanguage)134 TEST_F(OnDeviceHeadModelTest, NonEnglishLanguage) {
135   // Chinese.
136   auto suggestions =
137       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "谷");
138   EXPECT_THAT(suggestions, ElementsAre(Pair("谷歌", 32759)));
139 
140   // Japanese.
141   suggestions = OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4,
142                                                            "ガツガツ");
143   EXPECT_THAT(suggestions, ElementsAre(Pair("ガツガツしてる人", 32759)));
144 
145   // Korean.
146   suggestions =
147       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "비데 ");
148   EXPECT_THAT(suggestions, ElementsAre(Pair("비데 두꺼비", 32759)));
149 
150   // Russian.
151   suggestions =
152       OnDeviceHeadModel::GetSuggestionsForPrefix(model_filename_, 4, "пере");
153   EXPECT_THAT(suggestions, ElementsAre(Pair("переводчик", 32759)));
154 }
155