1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 #include <ostream>
21 
22 #include "frameworks/proto_logging/stats/atoms.pb.h"
23 #include "frameworks/proto_logging/stats/attribution_node.pb.h"
24 #include "packages/modules/StatsD/statsd/src/shell/shell_data.pb.h"
25 #include "packages/modules/StatsD/statsd/src/stats_log.pb.h"
26 
27 namespace android {
28 namespace os {
29 namespace statsd {
30 
31 using PackageInfo = UidMapping_PackageInfoSnapshot_PackageInfo;
32 
33 // clang-format off
34 
35 #define PROPERTY_MATCHER(typename, propname, matcher)                               \
36     testing::Property(#propname, &typename::propname, matcher(expected.propname()))
37 
38 #define REPEATED_PROPERTY_MATCHER(typename, propname, matcher)                      \
39     testing::Property(#propname, &typename::propname,                               \
40             testing::Pointwise(matcher(), expected.propname()))
41 
42 #define PROPERTY_EQ(typename, propname) PROPERTY_MATCHER(typename, propname, testing::Eq)
43 
44 #define REPEATED_PROPERTY_EQ(typename, propname)               \
45     REPEATED_PROPERTY_MATCHER(typename, propname, testing::Eq)
46 
47 /**
48  * Generate a GoogleTest equality matcher for a custom type specified by typename with the given
49  * properties.
50  *
51  * Example: For the protos:
52  *     message Bar {
53  *         optional int32 aa = 1;
54  *     }
55  *     message Foo {
56  *         optional int32 a = 1;
57  *         repeated float b = 2;
58  *         optional Bar bar = 3;
59  *         repeated Bar repeated_bar = 4;
60  *     }
61  * This will generate equality matchers for them called EqBar() and EqFoo():
62  *      EQ_MATCHER(Bar, PROPERTY_EQ(Bar, aa));
63  *      EQ_MATCHER(Foo,
64  *              PROPERTY_EQ(Foo, a),
65  *              PROPERTY_EQ(Foo, b),
66  *              PROPERTY_MATCHER(Foo, bar, EqBar),
67  *              REPEATED_PROPERTY_MATCHER(Foo, repeated_bar, EqBar)
68  *      );
69  */
70 #define EQ_MATCHER(typename, properties...)                                                   \
71     MATCHER(Eq##typename, " ") {                                                              \
72         return testing::Matches(Eq##typename(std::get<1>(arg)))(std::get<0>(arg));            \
73     }                                                                                         \
74     MATCHER_P(Eq##typename, expected, testing::PrintToString(expected)) {                     \
75         return testing::ExplainMatchResult(testing::AllOf(properties), arg, result_listener); \
76     }
77 
78 #define PROPERTY_PRINT(propname)                                                    \
79     if (obj.has_##propname()) {                                                     \
80         *os << #propname << ": " << testing::PrintToString(obj.propname()) << ", "; \
81     }
82 
83 #define REPEATED_PROPERTY_PRINT(propname)                                           \
84     if (obj.propname##_size() > 0) {                                                \
85         *os << #propname << ": " << testing::PrintToString(obj.propname()) << ", "; \
86     }
87 
88 /**
89  * Generates a method that teaches GoogleTest how to print a custom type specified by typename
90  * with the given properties.
91  * The equality matcher generated by EQ_MATCHER for the given typename will use this generated
92  * printer method to print the object when the matcher fails.
93  *
94  * Example: For the protos:
95  *     message Bar {
96  *         optional int32 aa = 1;
97  *     }
98  *     message Foo {
99  *         optional int32 a = 1;
100  *         repeated float b = 2;
101  *         optional Bar bar = 3;
102  *         repeated Bar repeated_bar = 4;
103  *     }
104  * This will generate printer methods for them:
105  *      TYPE_PRINTER(Bar, PROPERTY_PRINT(aa));
106  *      TYPE_PRINTER(Foo,
107  *              PROPERTY_PRINT(a)
108  *              PROPERTY_PRINT(b)
109  *              PROPERTY_PRINT(bar)
110  *              REPEATED_PROPERTY_PRINT(repeated_bar)
111  *      );
112  */
113 #define TYPE_PRINTER(typename, properties)                       \
114     inline void PrintTo(const typename& obj, std::ostream* os) { \
115         *os << #typename << ": { ";                              \
116         properties                                               \
117         *os << "}";                                              \
118     }
119 
120 EQ_MATCHER(PackageInfo,
121         PROPERTY_EQ(PackageInfo, version),
122         PROPERTY_EQ(PackageInfo, uid),
123         PROPERTY_EQ(PackageInfo, deleted),
124         PROPERTY_EQ(PackageInfo, truncated_certificate_hash),
125         PROPERTY_EQ(PackageInfo, name_hash),
126         PROPERTY_EQ(PackageInfo, version_string_hash),
127         PROPERTY_EQ(PackageInfo, name),
128         PROPERTY_EQ(PackageInfo, version_string),
129         PROPERTY_EQ(PackageInfo, installer_index),
130         PROPERTY_EQ(PackageInfo, installer_hash),
131         PROPERTY_EQ(PackageInfo, installer)
132 );
133 TYPE_PRINTER(PackageInfo,
134         PROPERTY_PRINT(version)
135         PROPERTY_PRINT(uid)
136         PROPERTY_PRINT(deleted)
137         PROPERTY_PRINT(truncated_certificate_hash)
138         PROPERTY_PRINT(name_hash)
139         PROPERTY_PRINT(version_string_hash)
140         PROPERTY_PRINT(name)
141         PROPERTY_PRINT(version_string)
142         PROPERTY_PRINT(installer_index)
143         PROPERTY_PRINT(installer_hash)
144         PROPERTY_PRINT(installer)
145 );
146 
147 EQ_MATCHER(AttributionNode,
148         PROPERTY_EQ(AttributionNode, uid),
149         PROPERTY_EQ(AttributionNode, tag)
150 );
151 TYPE_PRINTER(AttributionNode,
152         PROPERTY_PRINT(uid)
153         PROPERTY_PRINT(tag)
154 );
155 
156 EQ_MATCHER(ScreenStateChanged, PROPERTY_EQ(ScreenStateChanged, state));
157 TYPE_PRINTER(ScreenStateChanged, PROPERTY_PRINT(state));
158 
159 EQ_MATCHER(TrainExperimentIds,
160         REPEATED_PROPERTY_EQ(TrainExperimentIds, experiment_id)
161 );
162 TYPE_PRINTER(TrainExperimentIds, REPEATED_PROPERTY_PRINT(experiment_id));
163 
164 EQ_MATCHER(TestAtomReported,
165         REPEATED_PROPERTY_MATCHER(TestAtomReported, attribution_node, EqAttributionNode),
166         PROPERTY_EQ(TestAtomReported, int_field),
167         PROPERTY_EQ(TestAtomReported, long_field),
168         PROPERTY_EQ(TestAtomReported, float_field),
169         PROPERTY_EQ(TestAtomReported, string_field),
170         PROPERTY_EQ(TestAtomReported, boolean_field),
171         PROPERTY_EQ(TestAtomReported, state),
172         PROPERTY_MATCHER(TestAtomReported, bytes_field, EqTrainExperimentIds),
173         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_int_field),
174         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_long_field),
175         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_float_field),
176         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_string_field),
177         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_boolean_field),
178         REPEATED_PROPERTY_EQ(TestAtomReported, repeated_enum_field)
179 );
180 TYPE_PRINTER(TestAtomReported,
181         REPEATED_PROPERTY_PRINT(attribution_node)
182         PROPERTY_PRINT(int_field)
183         PROPERTY_PRINT(long_field)
184         PROPERTY_PRINT(float_field)
185         PROPERTY_PRINT(string_field)
186         PROPERTY_PRINT(boolean_field)
187         PROPERTY_PRINT(state)
188         PROPERTY_PRINT(bytes_field)
189         REPEATED_PROPERTY_PRINT(repeated_int_field)
190         REPEATED_PROPERTY_PRINT(repeated_long_field)
191         REPEATED_PROPERTY_PRINT(repeated_float_field)
192         REPEATED_PROPERTY_PRINT(repeated_string_field)
193         REPEATED_PROPERTY_PRINT(repeated_boolean_field)
194         REPEATED_PROPERTY_PRINT(repeated_enum_field)
195 );
196 
197 EQ_MATCHER(CpuActiveTime,
198         PROPERTY_EQ(CpuActiveTime, uid),
199         PROPERTY_EQ(CpuActiveTime, time_millis)
200 );
201 TYPE_PRINTER(CpuActiveTime,
202         PROPERTY_PRINT(uid)
203         PROPERTY_PRINT(time_millis)
204 );
205 
206 EQ_MATCHER(PluggedStateChanged, PROPERTY_EQ(PluggedStateChanged, state));
207 TYPE_PRINTER(PluggedStateChanged, PROPERTY_PRINT(state));
208 
209 EQ_MATCHER(WakelockStateChanged,
210         REPEATED_PROPERTY_MATCHER(WakelockStateChanged, attribution_node, EqAttributionNode),
211         PROPERTY_EQ(WakelockStateChanged, type),
212         PROPERTY_EQ(WakelockStateChanged, tag),
213         PROPERTY_EQ(WakelockStateChanged, state),
214         PROPERTY_EQ(WakelockStateChanged, process_state)
215 );
216 TYPE_PRINTER(WakelockStateChanged,
217         REPEATED_PROPERTY_PRINT(attribution_node)
218         PROPERTY_PRINT(type)
219         PROPERTY_PRINT(tag)
220         PROPERTY_PRINT(state)
221         PROPERTY_PRINT(process_state)
222 );
223 
224 EQ_MATCHER(Atom,
225         PROPERTY_MATCHER(Atom, screen_state_changed, EqScreenStateChanged),
226         PROPERTY_MATCHER(Atom, test_atom_reported, EqTestAtomReported),
227         PROPERTY_MATCHER(Atom, wakelock_state_changed, EqWakelockStateChanged)
228 );
229 TYPE_PRINTER(Atom,
230         PROPERTY_PRINT(screen_state_changed)
231         PROPERTY_PRINT(test_atom_reported)
232         PROPERTY_PRINT(wakelock_state_changed)
233 );
234 
235 EQ_MATCHER(ShellData,
236         REPEATED_PROPERTY_MATCHER(ShellData, atom, EqAtom),
237         REPEATED_PROPERTY_EQ(ShellData, elapsed_timestamp_nanos)
238 );
239 TYPE_PRINTER(ShellData,
240         REPEATED_PROPERTY_PRINT(atom)
241         REPEATED_PROPERTY_PRINT(elapsed_timestamp_nanos)
242 );
243 
244 // clang-format on
245 
246 }  // namespace statsd
247 }  // namespace os
248 }  // namespace android
249