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
24namespace android {
25namespace stats_log_api_gen {
26
27using std::map;
28using std::set;
29using std::vector;
30
31/**
32 * Return whether the set contains a vector of the elements provided.
33 */
34static bool
35set_contains_vector(const set<vector<java_type_t>>& 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 */
84TEST(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.size());
90
91    // IntAtom, AnotherIntAtom
92    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
93
94    // OutOfOrderAtom
95    EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
96
97    // AllTypesAtom
98    EXPECT_SET_CONTAINS_SIGNATURE(
99        atoms.signatures,
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 */
152TEST(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 */
162TEST(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 */
172TEST(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 */
183TEST(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 */
194TEST(CollationTest, FailBadAttributionNodePosition) {
195  Atoms atoms;
196  int errorCount =
197      collate_atoms(BadAttributionNodePosition::descriptor(), &atoms);
198
199  EXPECT_EQ(1, errorCount);
200}
201
202TEST(CollationTest, FailOnBadStateAtomOptions) {
203    Atoms atoms;
204    int errorCount = collate_atoms(BadStateAtoms::descriptor(), &atoms);
205
206    EXPECT_EQ(3, errorCount);
207}
208
209TEST(CollationTest, PassOnGoodStateAtomOptions) {
210    Atoms atoms;
211    int errorCount = collate_atoms(GoodStateAtoms::descriptor(), &atoms);
212    EXPECT_EQ(0, errorCount);
213}
214
215}  // namespace stats_log_api_gen
216}  // namespace android