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> ¶m) {
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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