1 /*
2  * Copyright 2018 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 #define __C2_GENERATE_GLOBAL_VARS__
18 
19 #include <set>
20 
21 #include <gtest/gtest.h>
22 
23 #include <C2ParamDef.h>
24 
25 #include <media/stagefright/foundation/ABuffer.h>
26 #include <media/stagefright/foundation/hexdump.h>
27 #include <ReflectedParamUpdater.h>
28 
29 namespace android {
30 
31 namespace {
32 
33 enum {
34     kParamIndexTestStart = 0x1000,
35     kParamIndexInt,
36     kParamIndexString,
37     kParamIndexComposite,
38     kParamIndexFlexString,
39 
40     kParamIndexLong = C2Param::TYPE_INDEX_VENDOR_START,
41 };
42 
43 typedef C2GlobalParam<C2Info, C2Int32Value, kParamIndexInt> C2IntInfo;
44 typedef C2GlobalParam<C2Info, C2Int64Value, kParamIndexLong> C2LongInfo;
45 
46 struct C2FixedSizeStringStruct {
47     char value[12];
48 
49     DEFINE_AND_DESCRIBE_BASE_C2STRUCT(FixedSizeString)
50     C2FIELD(value, "value")
51 };
52 typedef C2GlobalParam<C2Info, C2FixedSizeStringStruct, kParamIndexString> C2StringInfo;
53 
54 struct C2CompositeStruct {
55     int32_t i32;
56     uint64_t u64;
57     char str[12];
58     uint8_t blob[8];
59     uint8_t flexBlob[];
60 
61     C2CompositeStruct() = default;
62 
63     DEFINE_AND_DESCRIBE_BASE_FLEX_C2STRUCT(Composite, flexBlob)
64     C2FIELD(i32, "i32")
65     C2FIELD(u64, "u64")
66     C2FIELD(str, "str")
67     C2FIELD(blob, "blob")
68     C2FIELD(flexBlob, "flex-blob")
69 };
70 static_assert(C2CompositeStruct::FLEX_SIZE == 1, "");
71 static_assert(_C2FlexHelper<C2CompositeStruct>::FLEX_SIZE == 1, "");
72 typedef C2GlobalParam<C2Info, C2CompositeStruct, kParamIndexComposite> C2CompositeInfo;
73 
74 typedef C2GlobalParam<C2Info, C2StringValue, kParamIndexFlexString> C2FlexStringInfo;
75 
76 #define SUPPORTED_TYPES   \
77     C2IntInfo,            \
78     C2LongInfo,           \
79     C2StringInfo,         \
80     C2CompositeInfo,      \
81     C2FlexStringInfo
82 
83 template<typename... TYPES> struct describe_impl;
84 template<typename T, typename... TYPES> struct describe_impl<T, TYPES...> {
describeandroid::__anon8b1918600111::describe_impl85     static std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex index) {
86         if (index == T::CORE_INDEX) {
87             return std::make_unique<C2StructDescriptor>(T::CORE_INDEX, T::FieldList());
88         } else {
89             return describe_impl<TYPES...>::describe(index);
90         }
91     }
92 };
93 
94 template<> struct describe_impl<> {
describeandroid::__anon8b1918600111::describe_impl95     static std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex) {
96         return nullptr;
97     }
98 };
99 
GetName()100 template<typename T> const char *GetName()        { return nullptr; }
GetName()101 template<> const char *GetName<C2IntInfo>()       { return "int"; }
GetName()102 template<> const char *GetName<C2LongInfo>()      { return "long"; }
GetName()103 template<> const char *GetName<C2StringInfo>()    { return "string"; }
GetName()104 template<> const char *GetName<C2CompositeInfo>() { return "composite"; }
GetName()105 template<> const char *GetName<C2FlexStringInfo>() { return "flex-string"; }
106 
107 template<typename... TYPES> struct fill_descriptors_impl;
108 template<typename T, typename... TYPES> struct fill_descriptors_impl<T, TYPES...> {
fillandroid::__anon8b1918600111::fill_descriptors_impl109     static void fill(std::vector<std::shared_ptr<C2ParamDescriptor>> *vec) {
110         fill_descriptors_impl<TYPES...>::fill(vec);
111         vec->push_back(std::make_shared<C2ParamDescriptor>(
112                 T::PARAM_TYPE, C2ParamDescriptor::IS_PERSISTENT, GetName<T>()));
113     }
114 };
115 
116 template<> struct fill_descriptors_impl<> {
fillandroid::__anon8b1918600111::fill_descriptors_impl117     static void fill(std::vector<std::shared_ptr<C2ParamDescriptor>> *) {}
118 };
119 
CastParam(const std::unique_ptr<C2Param> & param)120 template<typename T> T *CastParam(const std::unique_ptr<C2Param> &param) {
121     return (T *)param.get();
122 }
123 
124 class ParamReflector : public C2ParamReflector {
125 public:
126     ParamReflector() = default;
127     ~ParamReflector() override = default;
128 
describe(C2Param::CoreIndex paramIndex) const129     std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override {
130         return describe_impl<SUPPORTED_TYPES>::describe(paramIndex);
131     }
132 };
133 
134 }  // namespace
135 
136 class ReflectedParamUpdaterTest : public ::testing::Test {
137 public:
ReflectedParamUpdaterTest()138     ReflectedParamUpdaterTest() : mReflector(new ParamReflector) {
139         fill_descriptors_impl<SUPPORTED_TYPES>::fill(&mDescriptors);
140     }
141 
142     std::shared_ptr<C2ParamReflector> mReflector;
143     std::vector<std::shared_ptr<C2ParamDescriptor>> mDescriptors;
144 };
145 
TEST_F(ReflectedParamUpdaterTest,SingleValueTest)146 TEST_F(ReflectedParamUpdaterTest, SingleValueTest) {
147     ReflectedParamUpdater updater;
148 
149     ReflectedParamUpdater::Dict msg;
150     msg.emplace("int.value", int32_t(12));
151     msg.emplace("vendor.long.value", int64_t(34));
152 
153     updater.addParamDesc(mReflector, mDescriptors);
154 
155     std::vector<C2Param::Index> indices;
156     updater.getParamIndicesFromMessage(msg, &indices);
157     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
158             [](const auto &value) { return (uint32_t)value == C2IntInfo::PARAM_TYPE; }));
159     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
160             [](const auto &value) { return (uint32_t)value == C2LongInfo::PARAM_TYPE; }));
161     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
162             [](const auto &value) { return (uint32_t)value == C2StringInfo::PARAM_TYPE; }));
163     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
164             [](const auto &value) { return (uint32_t)value == C2CompositeInfo::PARAM_TYPE; }));
165     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
166             [](const auto &value) { return (uint32_t)value == C2FlexStringInfo::PARAM_TYPE; }));
167 
168     std::vector<std::unique_ptr<C2Param>> params;
169     params.emplace_back(new C2IntInfo);
170     params.emplace_back(new C2LongInfo);
171     EXPECT_EQ(0, CastParam<C2IntInfo>(params[0])->value);
172     EXPECT_EQ(0, CastParam<C2LongInfo>(params[1])->value);
173 
174     updater.updateParamsFromMessage(msg, &params);
175     EXPECT_EQ(12, CastParam<C2IntInfo>(params[0])->value);
176     EXPECT_EQ(34, CastParam<C2LongInfo>(params[1])->value);
177 
178     C2Value c2Value;
179     int32_t int32Value = 0;
180     int64_t int64Value = 0;
181     msg = updater.getParams(params);
182     ASSERT_EQ(1u, msg.count("int.value"));
183     EXPECT_EQ(true, msg["int.value"].find(&c2Value));
184     EXPECT_EQ(true, c2Value.get(&int32Value));
185     EXPECT_EQ(12, int32Value);
186 
187     ASSERT_EQ(1u, msg.count("vendor.long.value"));
188     EXPECT_EQ(true, msg["vendor.long.value"].find(&c2Value));
189     EXPECT_EQ(true, c2Value.get(&int64Value));
190     EXPECT_EQ(34, int64Value);
191 }
192 
TEST_F(ReflectedParamUpdaterTest,StringTest)193 TEST_F(ReflectedParamUpdaterTest, StringTest) {
194     ReflectedParamUpdater updater;
195 
196     ReflectedParamUpdater::Dict msg;
197     msg.emplace("string.value", AString("56"));
198     msg.emplace("flex-string.value", AString("Some string"));
199     updater.addParamDesc(mReflector, mDescriptors);
200 
201     std::vector<C2Param::Index> indices;
202     updater.getParamIndicesFromMessage(msg, &indices);
203     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
204             [](const auto &value) { return (uint32_t)value == C2IntInfo::PARAM_TYPE; }));
205     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
206             [](const auto &value) { return (uint32_t)value == C2LongInfo::PARAM_TYPE; }));
207     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
208             [](const auto &value) { return (uint32_t)value == C2StringInfo::PARAM_TYPE; }));
209     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
210             [](const auto &value) { return (uint32_t)value == C2CompositeInfo::PARAM_TYPE; }));
211     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
212             [](const auto &value) { return (uint32_t)value == C2FlexStringInfo::PARAM_TYPE; }));
213 
214     std::vector<std::unique_ptr<C2Param>> params;
215     params.emplace_back(new C2StringInfo);
216     EXPECT_EQ(0, CastParam<C2StringInfo>(params[0])->value[0]);
217     params.emplace_back(C2FlexStringInfo::AllocUnique(0));
218     EXPECT_EQ(0u, CastParam<C2FlexStringInfo>(params[1])->flexCount());
219     char *flexStringData = &CastParam<C2FlexStringInfo>(params[1])->m.value[0];
220 
221     updater.updateParamsFromMessage(msg, &params);
222     EXPECT_STREQ("56", CastParam<C2StringInfo>(params[0])->value);
223     EXPECT_EQ(12u, CastParam<C2FlexStringInfo>(params[0])->flexCount());
224     EXPECT_STREQ("Some string", CastParam<C2FlexStringInfo>(params[1])->m.value);
225     EXPECT_NE(flexStringData, &CastParam<C2FlexStringInfo>(params[1])->m.value[0]);
226     flexStringData = &CastParam<C2FlexStringInfo>(params[1])->m.value[0];
227 
228     // verify truncation and in-place update
229     msg["string.value"] = ReflectedParamUpdater::Value(AString("1234567890ABCDE"));
230     msg["flex-string.value"] = ReflectedParamUpdater::Value(AString("abc"));
231     updater.updateParamsFromMessage(msg, &params);
232     EXPECT_STREQ("1234567890A", CastParam<C2StringInfo>(params[0])->value);
233     EXPECT_EQ(4u, CastParam<C2FlexStringInfo>(params[1])->flexCount());
234     EXPECT_STREQ("abc", CastParam<C2FlexStringInfo>(params[1])->m.value);
235     EXPECT_EQ(flexStringData, &CastParam<C2FlexStringInfo>(params[1])->m.value[0]);
236 
237     AString strValue;
238     msg = updater.getParams(params);
239     ASSERT_EQ(1u, msg.count("string.value"));
240     EXPECT_EQ(true, msg["string.value"].find(&strValue));
241     EXPECT_STREQ("1234567890A", strValue.c_str());
242 
243     ASSERT_EQ(1u, msg.count("flex-string.value"));
244     EXPECT_EQ(true, msg["flex-string.value"].find(&strValue));
245     EXPECT_STREQ("abc", strValue.c_str());
246 }
247 
TEST_F(ReflectedParamUpdaterTest,CompositeTest)248 TEST_F(ReflectedParamUpdaterTest, CompositeTest) {
249     ReflectedParamUpdater updater;
250 
251     ReflectedParamUpdater::Dict msg;
252     msg.emplace("composite.i32", int32_t(78));
253     msg.emplace("composite.u64", int64_t(910));
254     msg.emplace("composite.str", AString("1112"));
255     msg.emplace("composite.blob", ABuffer::CreateAsCopy("buffer08", 8));
256     msg.emplace("composite.flex-blob", ABuffer::CreateAsCopy("flex-buffer-14", 14));
257 
258     updater.addParamDesc(mReflector, mDescriptors);
259 
260     std::vector<C2Param::Index> indices;
261     updater.getParamIndicesFromMessage(msg, &indices);
262     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
263             [](const auto &value) { return (uint32_t)value == C2IntInfo::PARAM_TYPE; }));
264     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
265             [](const auto &value) { return (uint32_t)value == C2LongInfo::PARAM_TYPE; }));
266     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
267             [](const auto &value) { return (uint32_t)value == C2StringInfo::PARAM_TYPE; }));
268     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
269             [](const auto &value) { return (uint32_t)value == C2CompositeInfo::PARAM_TYPE; }));
270 
271     std::vector<std::unique_ptr<C2Param>> params;
272     params.emplace_back(C2CompositeInfo::AllocUnique(0));
273     EXPECT_EQ(0, CastParam<C2CompositeInfo>(params[0])->m.i32);
274     EXPECT_EQ(0u, CastParam<C2CompositeInfo>(params[0])->m.u64);
275     EXPECT_EQ(0, CastParam<C2CompositeInfo>(params[0])->m.str[0]);
276     EXPECT_EQ(0, memcmp("\0\0\0\0\0\0\0\0", CastParam<C2CompositeInfo>(params[0])->m.blob, 8));
277     EXPECT_EQ(0u, CastParam<C2CompositeInfo>(params[0])->flexCount());
278     uint8_t *flexBlobData = &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0];
279 
280     updater.updateParamsFromMessage(msg, &params);
281     EXPECT_EQ(78, CastParam<C2CompositeInfo>(params[0])->m.i32);
282     EXPECT_EQ(910u, CastParam<C2CompositeInfo>(params[0])->m.u64);
283     EXPECT_STREQ("1112", CastParam<C2CompositeInfo>(params[0])->m.str);
284     EXPECT_EQ(0, memcmp("buffer08", CastParam<C2CompositeInfo>(params[0])->m.blob, 8));
285     AString hex;
286     hexdump(CastParam<C2CompositeInfo>(params[0])->m.blob, 8, 0, &hex);
287     printf("%s\n", hex.c_str());
288     ASSERT_EQ(14u, CastParam<C2CompositeInfo>(params[0])->flexCount());
289     EXPECT_EQ(0, memcmp("flex-buffer-14", CastParam<C2CompositeInfo>(params[0])->m.flexBlob, 14));
290     EXPECT_NE(flexBlobData, &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0]);
291     flexBlobData = &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0];
292 
293     // test setting and zero extending shorter blob than allowed
294     msg.clear();
295     msg.emplace("composite.blob", ABuffer::CreateAsCopy("buf05", 5));
296     updater.updateParamsFromMessage(msg, &params);
297     EXPECT_EQ(0, memcmp("buf05\0\0\0", CastParam<C2CompositeInfo>(params[0])->m.blob, 8));
298     ASSERT_EQ(14u, CastParam<C2CompositeInfo>(params[0])->flexCount());
299     EXPECT_EQ(0, memcmp("flex-buffer-14", CastParam<C2CompositeInfo>(params[0])->m.flexBlob, 14));
300     EXPECT_EQ(flexBlobData, &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0]);
301 
302     // test setting and trimming larger blob than allowed
303     msg.clear();
304     msg.emplace("composite.blob", ABuffer::CreateAsCopy("ReallyLongBuffer", 16));
305     updater.updateParamsFromMessage(msg, &params);
306     EXPECT_EQ(0, memcmp("ReallyLo", CastParam<C2CompositeInfo>(params[0])->m.blob, 8));
307     ASSERT_EQ(14u, CastParam<C2CompositeInfo>(params[0])->flexCount());
308     EXPECT_EQ(0, memcmp("flex-buffer-14", CastParam<C2CompositeInfo>(params[0])->m.flexBlob, 14));
309     EXPECT_EQ(flexBlobData, &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0]);
310 
311     // test trimming flex blob in-place
312     msg.clear();
313     msg.emplace("composite.flex-blob", ABuffer::CreateAsCopy("buf05", 5));
314     updater.updateParamsFromMessage(msg, &params);
315     ASSERT_EQ(5u, CastParam<C2CompositeInfo>(params[0])->flexCount());
316     EXPECT_EQ(0, memcmp("buf05", CastParam<C2CompositeInfo>(params[0])->m.flexBlob, 5));
317     EXPECT_EQ(flexBlobData, &CastParam<C2CompositeInfo>(params[0])->m.flexBlob[0]);
318 }
319 
TEST_F(ReflectedParamUpdaterTest,CompositePartialTest)320 TEST_F(ReflectedParamUpdaterTest, CompositePartialTest) {
321     ReflectedParamUpdater updater;
322 
323     ReflectedParamUpdater::Dict msg;
324     msg.emplace("composite.i32", C2Value(1314));
325     msg.emplace("composite.str", AString("1516"));
326 
327     updater.addParamDesc(mReflector, mDescriptors);
328 
329     std::vector<C2Param::Index> indices;
330     updater.getParamIndicesFromMessage(msg, &indices);
331     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
332             [](const auto &value) { return (uint32_t)value == C2IntInfo::PARAM_TYPE; }));
333     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
334             [](const auto &value) { return (uint32_t)value == C2LongInfo::PARAM_TYPE; }));
335     EXPECT_EQ(0, std::count_if(indices.begin(), indices.end(),
336             [](const auto &value) { return (uint32_t)value == C2StringInfo::PARAM_TYPE; }));
337     EXPECT_EQ(1, std::count_if(indices.begin(), indices.end(),
338             [](const auto &value) { return (uint32_t)value == C2CompositeInfo::PARAM_TYPE; }));
339 
340     std::vector<std::unique_ptr<C2Param>> params;
341     params.emplace_back(C2CompositeInfo::AllocUnique(12u));
342     EXPECT_EQ(0, CastParam<C2CompositeInfo>(params[0])->m.i32);
343     EXPECT_EQ(0u, CastParam<C2CompositeInfo>(params[0])->m.u64);
344     EXPECT_EQ(0, CastParam<C2CompositeInfo>(params[0])->m.str[0]);
345 
346     updater.updateParamsFromMessage(msg, &params);
347     EXPECT_EQ(1314, CastParam<C2CompositeInfo>(params[0])->m.i32);
348     EXPECT_EQ(0u, CastParam<C2CompositeInfo>(params[0])->m.u64);
349     EXPECT_STREQ("1516", CastParam<C2CompositeInfo>(params[0])->m.str);
350 }
351 
352 } // namespace android
353