1 /*
2  * Copyright (C) 2017, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
20 #include "Collation.h"
21 
22 #include <stdio.h>
23 
24 namespace android {
25 namespace stats_log_api_gen {
26 
27 using std::map;
28 using std::set;
29 using std::vector;
30 
31 /**
32  * Return whether the set contains a vector of the elements provided.
33  */
34 static bool
set_contains_vector(const map<vector<java_type_t>,set<string>> & s,int count,...)35 set_contains_vector(const map<vector<java_type_t>, set<string>>& s, int count, ...)
36 {
37     va_list args;
38     vector<java_type_t> v;
39 
40     va_start(args, count);
41     for (int i=0; i<count; i++) {
42         v.push_back((java_type_t)va_arg(args, int));
43     }
44     va_end(args);
45 
46     return s.find(v) != s.end();
47 }
48 
49 /**
50  * Expect that the provided set contains the elements provided.
51  */
52 #define EXPECT_SET_CONTAINS_SIGNATURE(s, ...) \
53     do { \
54         int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \
55         EXPECT_TRUE(set_contains_vector(s, count, __VA_ARGS__)); \
56     } while(0)
57 
58 /** Expects that the provided atom has no enum values for any field. */
59 #define EXPECT_NO_ENUM_FIELD(atom) \
60     do { \
61         for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
62              field != atom->fields.end(); field++) { \
63             EXPECT_TRUE(field->enumValues.empty()); \
64         } \
65     } while(0)
66 
67 /** Expects that exactly one specific field has expected enum values. */
68 #define EXPECT_HAS_ENUM_FIELD(atom, field_name, values)        \
69     do { \
70         for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
71              field != atom->fields.end(); field++) { \
72             if (field->name == field_name) { \
73                 EXPECT_EQ(field->enumValues, values); \
74             } else { \
75                 EXPECT_TRUE(field->enumValues.empty()); \
76             } \
77         } \
78     } while(0)
79 
80 
81 /**
82  * Test a correct collation, with all the types.
83  */
TEST(CollationTest,CollateStats)84 TEST(CollationTest, CollateStats) {
85     Atoms atoms;
86     int errorCount = collate_atoms(Event::descriptor(), &atoms);
87 
88     EXPECT_EQ(0, errorCount);
89     EXPECT_EQ(3ul, atoms.signatures_to_modules.size());
90 
91     // IntAtom, AnotherIntAtom
92     EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
93 
94     // OutOfOrderAtom
95     EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT);
96 
97     // AllTypesAtom
98     EXPECT_SET_CONTAINS_SIGNATURE(
99         atoms.signatures_to_modules,
100         JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
101         JAVA_TYPE_DOUBLE,            // double
102         JAVA_TYPE_FLOAT,             // float
103         JAVA_TYPE_LONG,              // int64
104         JAVA_TYPE_LONG,              // uint64
105         JAVA_TYPE_INT,               // int32
106         JAVA_TYPE_LONG,              // fixed64
107         JAVA_TYPE_INT,               // fixed32
108         JAVA_TYPE_BOOLEAN,           // bool
109         JAVA_TYPE_STRING,            // string
110         JAVA_TYPE_INT,               // uint32
111         JAVA_TYPE_INT,               // AnEnum
112         JAVA_TYPE_INT,               // sfixed32
113         JAVA_TYPE_LONG,              // sfixed64
114         JAVA_TYPE_INT,               // sint32
115         JAVA_TYPE_LONG               // sint64
116     );
117 
118     set<AtomDecl>::const_iterator atom = atoms.decls.begin();
119     EXPECT_EQ(1, atom->code);
120     EXPECT_EQ("int_atom", atom->name);
121     EXPECT_EQ("IntAtom", atom->message);
122     EXPECT_NO_ENUM_FIELD(atom);
123     atom++;
124 
125     EXPECT_EQ(2, atom->code);
126     EXPECT_EQ("out_of_order_atom", atom->name);
127     EXPECT_EQ("OutOfOrderAtom", atom->message);
128     EXPECT_NO_ENUM_FIELD(atom);
129     atom++;
130 
131     EXPECT_EQ(3, atom->code);
132     EXPECT_EQ("another_int_atom", atom->name);
133     EXPECT_EQ("AnotherIntAtom", atom->message);
134     EXPECT_NO_ENUM_FIELD(atom);
135     atom++;
136 
137     EXPECT_EQ(4, atom->code);
138     EXPECT_EQ("all_types_atom", atom->name);
139     EXPECT_EQ("AllTypesAtom", atom->message);
140     map<int, string> enumValues;
141     enumValues[0] = "VALUE0";
142     enumValues[1] = "VALUE1";
143     EXPECT_HAS_ENUM_FIELD(atom, "enum_field", enumValues);
144     atom++;
145 
146     EXPECT_TRUE(atom == atoms.decls.end());
147 }
148 
149 /**
150  * Test that event class that contains stuff other than the atoms is rejected.
151  */
TEST(CollationTest,NonMessageTypeFails)152 TEST(CollationTest, NonMessageTypeFails) {
153     Atoms atoms;
154     int errorCount = collate_atoms(IntAtom::descriptor(), &atoms);
155 
156     EXPECT_EQ(1, errorCount);
157 }
158 
159 /**
160  * Test that atoms that have non-primitive types are rejected.
161  */
TEST(CollationTest,FailOnBadTypes)162 TEST(CollationTest, FailOnBadTypes) {
163     Atoms atoms;
164     int errorCount = collate_atoms(BadTypesEvent::descriptor(), &atoms);
165 
166     EXPECT_EQ(2, errorCount);
167 }
168 
169 /**
170  * Test that atoms that skip field numbers (in the first position) are rejected.
171  */
TEST(CollationTest,FailOnSkippedFieldsSingle)172 TEST(CollationTest, FailOnSkippedFieldsSingle) {
173     Atoms atoms;
174     int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), &atoms);
175 
176     EXPECT_EQ(1, errorCount);
177 }
178 
179 /**
180  * Test that atoms that skip field numbers (not in the first position, and multiple
181  * times) are rejected.
182  */
TEST(CollationTest,FailOnSkippedFieldsMultiple)183 TEST(CollationTest, FailOnSkippedFieldsMultiple) {
184     Atoms atoms;
185     int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), &atoms);
186 
187     EXPECT_EQ(2, errorCount);
188 }
189 
190 /**
191  * Test that atoms that have an attribution chain not in the first position are
192  * rejected.
193  */
TEST(CollationTest,FailBadAttributionNodePosition)194 TEST(CollationTest, FailBadAttributionNodePosition) {
195   Atoms atoms;
196   int errorCount =
197       collate_atoms(BadAttributionNodePosition::descriptor(), &atoms);
198 
199   EXPECT_EQ(1, errorCount);
200 }
201 
TEST(CollationTest,FailOnBadStateAtomOptions)202 TEST(CollationTest, FailOnBadStateAtomOptions) {
203     Atoms atoms;
204     int errorCount = collate_atoms(BadStateAtoms::descriptor(), &atoms);
205 
206     EXPECT_EQ(3, errorCount);
207 }
208 
TEST(CollationTest,PassOnGoodStateAtomOptions)209 TEST(CollationTest, PassOnGoodStateAtomOptions) {
210     Atoms atoms;
211     int errorCount = collate_atoms(GoodStateAtoms::descriptor(), &atoms);
212     EXPECT_EQ(0, errorCount);
213 }
214 
TEST(CollationTest,PassOnGoodBinaryFieldAtom)215 TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
216     Atoms atoms;
217     int errorCount =
218             collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), &atoms);
219     EXPECT_EQ(0, errorCount);
220 }
221 
TEST(CollationTest,FailOnBadBinaryFieldAtom)222 TEST(CollationTest, FailOnBadBinaryFieldAtom) {
223     Atoms atoms;
224     int errorCount =
225             collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), &atoms);
226     EXPECT_TRUE(errorCount > 0);
227 }
228 
TEST(CollationTest,PassOnWhitelistedAtom)229 TEST(CollationTest, PassOnWhitelistedAtom) {
230     Atoms atoms;
231     int errorCount = collate_atoms(ListedAtoms::descriptor(), &atoms);
232     EXPECT_EQ(errorCount, 0);
233     EXPECT_EQ(atoms.decls.size(), 2ul);
234 }
235 
TEST(CollationTest,RecogniseWhitelistedAtom)236 TEST(CollationTest, RecogniseWhitelistedAtom) {
237     Atoms atoms;
238     collate_atoms(ListedAtoms::descriptor(), &atoms);
239     for (const auto& atomDecl : atoms.decls) {
240         if (atomDecl.code == 1) {
241             EXPECT_TRUE(atomDecl.whitelisted);
242         } else {
243             EXPECT_FALSE(atomDecl.whitelisted);
244         }
245     }
246 }
247 
TEST(CollationTest,PassOnLogFromModuleAtom)248 TEST(CollationTest, PassOnLogFromModuleAtom) {
249     Atoms atoms;
250     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
251     EXPECT_EQ(errorCount, 0);
252     EXPECT_EQ(atoms.decls.size(), 3ul);
253 }
254 
TEST(CollationTest,RecognizeModuleAtom)255 TEST(CollationTest, RecognizeModuleAtom) {
256     Atoms atoms;
257     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
258     EXPECT_EQ(errorCount, 0);
259     EXPECT_EQ(atoms.decls.size(), 3ul);
260     for (const auto& atomDecl: atoms.decls) {
261         if (atomDecl.code == 1) {
262             EXPECT_TRUE(atomDecl.hasModule);
263             EXPECT_EQ(atomDecl.moduleName, "module1");
264         } else if (atomDecl.code == 2) {
265             EXPECT_TRUE(atomDecl.hasModule);
266             EXPECT_EQ(atomDecl.moduleName, "module2");
267         } else {
268             EXPECT_FALSE(atomDecl.hasModule);
269         }
270     }
271 
272     EXPECT_EQ(atoms.signatures_to_modules.size(), 2u);
273     EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
274     EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING);
275     for (auto signature_to_modules_it : atoms.signatures_to_modules) {
276         vector<java_type_t> signature = signature_to_modules_it.first;
277         if (signature[0] == JAVA_TYPE_STRING) {
278             EXPECT_EQ(signature_to_modules_it.second.size(), 0u);
279         } else if (signature[0] == JAVA_TYPE_INT) {
280             set<string> modules = signature_to_modules_it.second;
281             EXPECT_EQ(modules.size(), 2u);
282             // Assert that the set contains "module1" and "module2".
283             EXPECT_NE(modules.find("module1"), modules.end());
284             EXPECT_NE(modules.find("module2"), modules.end());
285         }
286     }
287 }
288 
289 }  // namespace stats_log_api_gen
290 }  // namespace android