1 // Copyright 2018 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 #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_TEST_UTIL_H_
6 #define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_TEST_UTIL_H_
7 
8 #include <string>
9 
10 #include "chrome/browser/ui/app_list/search/search_result_ranker/app_launch_predictor.pb.h"
11 #include "chrome/browser/ui/app_list/search/search_result_ranker/frecency_store.pb.h"
12 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_predictor.pb.h"
13 #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.pb.h"
14 #include "third_party/protobuf/src/google/protobuf/stubs/mathutil.h"
15 
16 namespace app_list {
17 
18 // Returns whether two protos are equivalent, which is defined as:
19 //   (1) each integer field has the same value.
20 //   (2) each float field has to be AlmostEqual.
21 //   (3) each map field should have same pairs of key-value.
22 //   (4) each repeated field should have the same values, in the same order.
23 //   (5) each proto field is defined recursively.
24 // Note:
25 //   (1) This function should only be used for MessageLite where reflection is
26 //       not supported; otherwise MessageDifferencer is preferred.
27 //   (2) This function will not support any proto by default; new proto (and all
28 //       its sub-proto) should be added with macro DEFINE_EQUIVTO_PROTO_LITE_*.
29 template <typename Proto>
30 bool EquivToProtoLite(const Proto& p1, const Proto& p2);
31 
32 namespace internal {
33 
34 // General templated class for implementation of EquivToProtoLite;
35 template <typename Proto>
36 class EquivToProtoLiteImpl {};
37 
38 // Specialized by std::string.
39 template <>
40 class EquivToProtoLiteImpl<std::string> {
41  public:
operator()42   bool operator()(const std::string& p1, const std::string& p2) {
43     return p1 == p2;
44   }
45 };
46 
47 // Specialized by int32_t.
48 template <>
49 class EquivToProtoLiteImpl<int32_t> {
50  public:
operator()51   bool operator()(const int32_t p1, const int32_t p2) { return p1 == p2; }
52 };
53 
54 // Specialized by unsigned int.
55 template <>
56 class EquivToProtoLiteImpl<unsigned int> {
57  public:
operator()58   bool operator()(const unsigned int p1, const unsigned int p2) {
59     return p1 == p2;
60   }
61 };
62 
63 // Specialized by float.
64 template <>
65 class EquivToProtoLiteImpl<float> {
66  public:
operator()67   bool operator()(const float p1, const float p2) {
68     return google::protobuf::MathUtil::AlmostEquals(p1, p2);
69   }
70 };
71 
72 // Specialized by unsigned long.
73 template <>
74 class EquivToProtoLiteImpl<unsigned long> {
75  public:
operator()76   bool operator()(const unsigned long p1, const unsigned long p2) {
77     return p1 == p2;
78   }
79 };
80 
81 // Specialized by unsigned long long.
82 template <>
83 class EquivToProtoLiteImpl<unsigned long long> {
84  public:
operator()85   bool operator()(const unsigned long long p1, const unsigned long long p2) {
86     return p1 == p2;
87   }
88 };
89 
90 // Specialized by google::protobuf::Map.
91 template <typename K, typename V>
92 class EquivToProtoLiteImpl<google::protobuf::Map<K, V>> {
93  public:
94   using Map = google::protobuf::Map<K, V>;
operator()95   bool operator()(const Map& p1, const Map& p2) {
96     if (p1.size() != p2.size())
97       return false;
98     for (const auto& pair : p1) {
99       const auto find_in_p2 = p2.find(pair.first);
100       if (find_in_p2 == p2.end())
101         return false;
102       if (!EquivToProtoLite(pair.second, find_in_p2->second))
103         return false;
104     }
105 
106     return true;
107   }
108 };
109 
110 // Specialized by RepeatedPtrField.
111 template <typename T>
112 class EquivToProtoLiteImpl<google::protobuf::RepeatedPtrField<T>> {
113  public:
114   using Repeated = google::protobuf::RepeatedPtrField<T>;
operator()115   bool operator()(const Repeated& p1, const Repeated& p2) {
116     if (p1.size() != p2.size())
117       return false;
118 
119     for (int i = 0; i < p1.size(); ++i) {
120       const auto& v1 = p1.Get(i);
121       const auto& v2 = p2.Get(i);
122 
123       if (!EquivToProtoLite(v1, v2))
124         return false;
125     }
126 
127     return true;
128   }
129 };
130 
131 #define DEFINE_EQUIVTO_PROTO_LITE_DEFAULT(Proto)               \
132   template <>                                                  \
133   class EquivToProtoLiteImpl<Proto> {                          \
134    public:                                                     \
135     bool operator()(const Proto& t1, const Proto& t2) {        \
136       return t1.SerializeAsString() == t2.SerializeAsString(); \
137     }                                                          \
138   }
139 
140 #define DEFINE_EQUIVTO_PROTO_LITE_1(Proto, f1)          \
141   template <>                                           \
142   class EquivToProtoLiteImpl<Proto> {                   \
143    public:                                              \
144     bool operator()(const Proto& t1, const Proto& t2) { \
145       return EquivToProtoLite(t1.f1(), t2.f1());        \
146     }                                                   \
147   }
148 
149 #define DEFINE_EQUIVTO_PROTO_LITE_2(Proto, f1, f2)      \
150   template <>                                           \
151   class EquivToProtoLiteImpl<Proto> {                   \
152    public:                                              \
153     bool operator()(const Proto& t1, const Proto& t2) { \
154       return EquivToProtoLite(t1.f1(), t2.f1()) &&      \
155              EquivToProtoLite(t1.f2(), t2.f2());        \
156     }                                                   \
157   }
158 
159 #define DEFINE_EQUIVTO_PROTO_LITE_3(Proto, f1, f2, f3)  \
160   template <>                                           \
161   class EquivToProtoLiteImpl<Proto> {                   \
162    public:                                              \
163     bool operator()(const Proto& t1, const Proto& t2) { \
164       return EquivToProtoLite(t1.f1(), t2.f1()) &&      \
165              EquivToProtoLite(t1.f2(), t2.f2()) &&      \
166              EquivToProtoLite(t1.f3(), t2.f3());        \
167     }                                                   \
168   }
169 
170 #define DEFINE_EQUIVTO_PROTO_LITE_4(Proto, f1, f2, f3, f4) \
171   template <>                                              \
172   class EquivToProtoLiteImpl<Proto> {                      \
173    public:                                                 \
174     bool operator()(const Proto& t1, const Proto& t2) {    \
175       return EquivToProtoLite(t1.f1(), t2.f1()) &&         \
176              EquivToProtoLite(t1.f2(), t2.f2()) &&         \
177              EquivToProtoLite(t1.f3(), t2.f3()) &&         \
178              EquivToProtoLite(t1.f4(), t2.f4());           \
179     }                                                      \
180   }
181 
182 #define DEFINE_EQUIVTO_PROTO_LITE_5(Proto, f1, f2, f3, f4, f5) \
183   template <>                                                  \
184   class EquivToProtoLiteImpl<Proto> {                          \
185    public:                                                     \
186     bool operator()(const Proto& t1, const Proto& t2) {        \
187       return EquivToProtoLite(t1.f1(), t2.f1()) &&             \
188              EquivToProtoLite(t1.f2(), t2.f2()) &&             \
189              EquivToProtoLite(t1.f3(), t2.f3()) &&             \
190              EquivToProtoLite(t1.f4(), t2.f4()) &&             \
191              EquivToProtoLite(t1.f5(), t2.f5());               \
192     }                                                          \
193   }
194 
195 // Macro that generates a specialization for |Proto| with four fields.
196 #define DEFINE_EQUIVTO_PROTO_LITE_6(Proto, f1, f2, f3, f4, f5, f6) \
197   template <>                                                      \
198   class EquivToProtoLiteImpl<Proto> {                              \
199    public:                                                         \
200     bool operator()(const Proto& t1, const Proto& t2) {            \
201       return EquivToProtoLite(t1.f1(), t2.f1()) &&                 \
202              EquivToProtoLite(t1.f2(), t2.f2()) &&                 \
203              EquivToProtoLite(t1.f3(), t2.f3()) &&                 \
204              EquivToProtoLite(t1.f4(), t2.f4()) &&                 \
205              EquivToProtoLite(t1.f5(), t2.f5()) &&                 \
206              EquivToProtoLite(t1.f6(), t2.f6());                   \
207     }                                                              \
208   }
209 
210 DEFINE_EQUIVTO_PROTO_LITE_3(AppLaunchPredictorProto,
211                             fake_app_launch_predictor,
212                             hour_app_launch_predictor,
213                             serialized_mrfu_app_launch_predictor);
214 
215 DEFINE_EQUIVTO_PROTO_LITE_1(FakeAppLaunchPredictorProto, rank_result);
216 
217 DEFINE_EQUIVTO_PROTO_LITE_1(FakePredictorProto, counts);
218 
219 DEFINE_EQUIVTO_PROTO_LITE_5(FrecencyStoreProto,
220                             values,
221                             value_limit,
222                             decay_coeff,
223                             num_updates,
224                             next_id);
225 
226 DEFINE_EQUIVTO_PROTO_LITE_3(FrecencyStoreProto_ValueData,
227                             id,
228                             last_score,
229                             last_num_updates);
230 
231 DEFINE_EQUIVTO_PROTO_LITE_1(HourBinPredictorProto, binned_frequency_table);
232 
233 DEFINE_EQUIVTO_PROTO_LITE_2(HourBinPredictorProto_FrequencyTable,
234                             total_counts,
235                             frequency);
236 
237 DEFINE_EQUIVTO_PROTO_LITE_1(HourAppLaunchPredictorProto,
238                             binned_frequency_table);
239 
240 DEFINE_EQUIVTO_PROTO_LITE_2(HourAppLaunchPredictorProto_FrequencyTable,
241                             total_counts,
242                             frequency);
243 
244 DEFINE_EQUIVTO_PROTO_LITE_2(RecurrencePredictorProto,
245                             fake_predictor,
246                             frecency_predictor);
247 
248 DEFINE_EQUIVTO_PROTO_LITE_2(RecurrenceRankerProto, config_hash, predictor);
249 
250 DEFINE_EQUIVTO_PROTO_LITE_2(SerializedMrfuAppLaunchPredictorProto,
251                             num_of_trains,
252                             scores);
253 
254 DEFINE_EQUIVTO_PROTO_LITE_2(SerializedMrfuAppLaunchPredictorProto_Score,
255                             num_of_trains_at_last_update,
256                             last_score);
257 
258 DEFINE_EQUIVTO_PROTO_LITE_2(FrecencyPredictorProto, targets, num_updates);
259 
260 DEFINE_EQUIVTO_PROTO_LITE_2(FrecencyPredictorProto_TargetData,
261                             last_score,
262                             last_num_updates);
263 
264 }  // namespace internal
265 
266 template <typename Proto>
EquivToProtoLite(const Proto & p1,const Proto & p2)267 bool EquivToProtoLite(const Proto& p1, const Proto& p2) {
268   return internal::EquivToProtoLiteImpl<Proto>()(p1, p2);
269 }
270 
271 }  // namespace app_list
272 
273 #endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LAUNCH_PREDICTOR_TEST_UTIL_H_
274