• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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 #define LOG_TAG "C2ComponentInterface_test"
18 
19 #include <dlfcn.h>
20 #include <stdio.h>
21 
22 #include <gtest/gtest.h>
23 #include <utils/Log.h>
24 
25 #include <C2Component.h>
26 #include <C2Config.h>
27 #include <util/C2InterfaceHelper.h>
28 #include <C2Param.h>
29 
30 #if !defined(UNUSED)
31 #define UNUSED(expr)                                                           \
32   do {                                                                         \
33       (void)(expr);                                                            \
34   } while (0)
35 
36 #endif //!defined(UNUSED)
37 
38 namespace android {
39 
alloc_unique_cstr(const char * cstr)40 template <class T> std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
41     size_t len = strlen(cstr);
42     std::unique_ptr<T> ptr = T::AllocUnique(len);
43     memcpy(ptr->m.value, cstr, len);
44     return ptr;
45 }
46 
47 class C2CompIntfTest : public ::testing::Test {
48 protected:
C2CompIntfTest()49     C2CompIntfTest() {}
~C2CompIntfTest()50     ~C2CompIntfTest() override {}
51 
setComponent(std::shared_ptr<C2ComponentInterface> intf)52     void setComponent(std::shared_ptr<C2ComponentInterface> intf) {
53         mIntf = intf;
54     }
55 
resetResults()56     void resetResults() {
57         mIntf = nullptr;
58         mParamResults.clear();
59     }
60 
61     template <typename T> void testUnsupportedParam();
62 
63     template <typename T> void testSupportedParam();
64 
65     // testReadOnlyParam() and testWritableParam() are the main functions for testing a parameter.
66     // A caller should find out if a tested parameter is read-only or writable before calling them
67     // and it must call one of the corresponded them.
68 
69     // If a parameter is read-only this is called.
70     // Test read-only parameter |preParam|. The test expects failure while config() with |newParam|,
71     // and make sure |preParam| stay unchanged.
72     template <typename T>
73     void testReadOnlyParam(const T &preParam, const T &newParam);
74 
75     // If a parameter is writable this is called.
76     // Test one filed |writableField| for given writable parameter |param|.
77     // |validValues| contains all values obtained from querySupportedValues() for |writableField|.
78     // The test checks validity for config() with each value, and make sure values are config-ed
79     // by query() them out. |invalidValues| contains some values which are not in |validValues|.
80     // The test expects C2_BAD_VALUE while config() with these values,
81     // and |param| should stay unchanged.
82     template <typename TParam, typename TRealField, typename TField>
83     void testWritableParam(TParam *const param, TRealField *const writableField,
84                            const std::vector<TField> &validValues,
85                            const std::vector<TField> &invalidValues);
86 
87     // Test all the defined parameters in C2Param.h.
88     void testMain(std::shared_ptr<C2ComponentInterface> intf,
89                   const std::string &componentName);
90 
91     // Check permission of parameter type |T| for testing interface.
92     // This should be called first of the testing per parameter type,
93     // therefore different testing process is applied according to the permission type.
94     template <typename T>
95     void checkParamPermission(
96             int *const writable,
97             const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams);
98 
99 private:
100     enum ParamPermission : int {
101         WRITABLE,
102         READONLY,
103         UNSUPPORTED,
104     };
105 
106     struct paramTestInfo {
107         std::string name;
108         int result;
paramTestInfoandroid::C2CompIntfTest::paramTestInfo109         paramTestInfo(const char *name_, int result_)
110             : name(name_), result(result_) {}
111     };
112 
113     // queryOnStack() and queryonHeap() both call an interface's query_vb() and
114     // check if a component has a parameter whose type is |T|.
115     // If a component has, the value should be copied into an argument, that is
116     // |p| in queryOnStack() and |heapParams| in queryOnHeap().
117     // The return value is c2_status_t (e.g. C2_OK).
118     template <typename T> c2_status_t queryOnStack(T *const p);
119 
120     template <typename T>
121     c2_status_t queryOnHeap(const T &p,
122                          std::vector<std::unique_ptr<C2Param>> *const heapParams);
123 
124     // Get a value whose type is |T| in a component. The value is copied to |param|.
125     // This should be called only if a component has the parameter.
126     template <typename T> void getValue(T *const param);
127 
128     // Check if the parameter's value in component is equal to |expected| and
129     // queryOnStack() and queryOnHeap() are succeeded. When this function called,
130     // it should be guaranteed a component has the parameter.
131     template <typename T> void queryParamAsExpected(const T &expected);
132 
133     // Test if query functions works correctly for supported parameters.
134     // "Support" means here a component has the parameter.
135     template <typename T> void querySupportedParam();
136 
137     // Test query functions works correctly for unsupported parameters.
138     // "Unsupport" means here a component doesn't have the parameter.
139     template <typename T> void queryUnsupportedParam();
140 
141     // Execute an interface's config_vb(). |T| is a single parameter type, not std::vector.
142     // config() creates std::vector<C2Param *> {p} and passes it to config_vb().
143     template <typename T>
144     c2_status_t
145     config(T *const p,
146            std::vector<std::unique_ptr<C2SettingResult>> *const failures);
147 
148     // Test if config works correctly for read-only parameters.
149     // Because the failure of config() is assumed, |newParam| doesn't matter.
150     template <typename T> void configReadOnlyParam(const T &newParam);
151 
152     // Test if config works correctly for writable parameters.
153     // This changes the parameter's value to |newParam|.
154     // |stConfig| is a return value of config().
155     template <typename T> void configWritableParamValidValue(const T &newParam, c2_status_t *stConfig);
156 
157     // Test if config works correctly in the case an invalid value |newParam| is tried to write
158     // to an writable parameter.
159     template <typename T> void configWritableParamInvalidValue(const T &newParam);
160 
161     // Create values for testing from |validValueInfos|. The values are returned as arguments.
162     // |validValues| : valid values, which can be written for the parameter.
163     // |InvalidValues| : invalid values, which cannot be written for the parameter.
164     //                   config() should be failed if these values are used as new values.
165     // This function should be called only for writable and supported parameters.
166     template <typename TField>
167     void getTestValues(const C2FieldSupportedValues &validValueInfos,
168                        std::vector<TField> *const validValues,
169                        std::vector<TField> *const invalidValues);
170 
171     // Output the summary of test results. Categorizes parameters with their configuration.
172     void outputResults(const std::string &name);
173 
174     std::shared_ptr<C2ComponentInterface> mIntf;
175     std::vector<paramTestInfo> mParamResults;
176     std::string mCurrentParamName;
177 };
178 
179 // factory function
180 // TODO(hiroh): Add factory functions for other types.
makeParam()181 template <typename T> std::unique_ptr<T> makeParam() {
182     return std::make_unique<T>();
183 }
184 
makeParam()185 template <> std::unique_ptr<C2PortMimeConfig::input> makeParam() {
186     // TODO(hiroh): Set more precise length.
187     return C2PortMimeConfig::input::AllocUnique(100);
188 }
189 
190 #define TRACED_FAILURE(func)                            \
191     do {                                                \
192         SCOPED_TRACE(mCurrentParamName);             \
193         func;                                           \
194         if (::testing::Test::HasFatalFailure()) {       \
195             return;                                     \
196         }                                               \
197     } while (false)
198 
queryOnStack(T * const p)199 template <typename T> c2_status_t C2CompIntfTest::queryOnStack(T *const p) {
200     std::vector<C2Param*> stackParams{p};
201     return mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr);
202 }
203 
204 template <typename T>
queryOnHeap(const T & p,std::vector<std::unique_ptr<C2Param>> * const heapParams)205 c2_status_t C2CompIntfTest::queryOnHeap(
206         const T &p, std::vector<std::unique_ptr<C2Param>> *const heapParams) {
207     uint32_t index = p.index() & ~0x03FE0000;
208     if (p.forStream()) {
209         index |= ((p.stream() << 17) & 0x01FE0000) | 0x02000000;
210     }
211     return mIntf->query_vb({}, {index}, C2_DONT_BLOCK, heapParams);
212 }
213 
getValue(T * const param)214 template <typename T> void C2CompIntfTest::getValue(T *const param) {
215     // When getValue() is called, a component has to have the parameter.
216     ASSERT_EQ(C2_OK, queryOnStack(param));
217 }
218 
219 template <typename T>
queryParamAsExpected(const T & expected)220 void C2CompIntfTest::queryParamAsExpected(const T &expected) {
221     // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
222     // Note that all the current supported parameters are non-flex params.
223     T stack;
224     std::unique_ptr<T> pHeap = makeParam<T>();
225     std::vector<std::unique_ptr<C2Param>> heapParams;
226 
227     ASSERT_EQ(C2_OK, queryOnStack(&stack));
228 
229     // |stack| is a parameter value. The parameter size shouldn't be 0.
230     EXPECT_NE(0u, stack.size());
231     EXPECT_EQ(stack, expected);
232 
233     ASSERT_EQ(C2_OK, queryOnHeap(*pHeap, &heapParams));
234 
235     // |*heapParams[0]| is a parameter value. The size of |heapParams| has to be one.
236     ASSERT_EQ(1u, heapParams.size());
237     EXPECT_TRUE(heapParams[0]);
238     EXPECT_EQ(*heapParams[0], expected);
239 }
240 
querySupportedParam()241 template <typename T> void C2CompIntfTest::querySupportedParam() {
242     std::unique_ptr<T> param = makeParam<T>();
243     // The current parameter's value is acquired by getValue(), which should be succeeded.
244     getValue(param.get());
245     queryParamAsExpected(*param);
246 }
247 
queryUnsupportedParam()248 template <typename T> void C2CompIntfTest::queryUnsupportedParam() {
249     // TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
250     // Note that all the current supported parameters are non-flex params.
251     T stack;
252     std::unique_ptr<T> pHeap = makeParam<T>();
253     std::vector<std::unique_ptr<C2Param>> heapParams;
254     // If a component doesn't have the parameter, queryOnStack() and queryOnHeap()
255     // should return C2_BAD_INDEX.
256     ASSERT_EQ(C2_BAD_INDEX, queryOnStack(&stack));
257     EXPECT_FALSE(stack);
258     ASSERT_EQ(C2_BAD_INDEX, queryOnHeap(*pHeap, &heapParams));
259     EXPECT_EQ(0u, heapParams.size());
260 }
261 
262 template <typename T>
config(T * const p,std::vector<std::unique_ptr<C2SettingResult>> * const failures)263 c2_status_t C2CompIntfTest::config(
264         T *const p, std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
265     std::vector<C2Param*> params{p};
266     return mIntf->config_vb(params, C2_DONT_BLOCK, failures);
267 }
268 
269 // Create a new parameter copied from |p|.
makeParamFrom(const T & p)270 template <typename T> std::unique_ptr<T> makeParamFrom(const T &p) {
271     std::unique_ptr<T> retP = makeParam<T>();
272     EXPECT_TRUE(retP->updateFrom(p));
273     EXPECT_TRUE(memcmp(retP.get(), &p, sizeof(T)) == 0);
274     return retP;
275 }
276 
277 template <typename T>
configReadOnlyParam(const T & newParam)278 void C2CompIntfTest::configReadOnlyParam(const T &newParam) {
279     std::unique_ptr<T> p = makeParamFrom(newParam);
280 
281     std::vector<C2Param*> params{p.get()};
282     std::vector<std::unique_ptr<C2SettingResult>> failures;
283 
284     // config_vb should be failed because a parameter is read-only.
285     ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
286     ASSERT_EQ(1u, failures.size());
287     EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure);
288 }
289 
290 template <typename T>
configWritableParamValidValue(const T & newParam,c2_status_t * configResult)291 void C2CompIntfTest::configWritableParamValidValue(const T &newParam, c2_status_t *configResult) {
292     std::unique_ptr<T> p = makeParamFrom(newParam);
293 
294     std::vector<C2Param*> params{p.get()};
295     std::vector<std::unique_ptr<C2SettingResult>> failures;
296     // In most cases, config_vb return C2_OK and the parameter's value should be changed
297     // to |newParam|, which is confirmed in a caller of configWritableParamValueValue().
298     // However, this can return ~~~~ and the parameter's values is not changed,
299     // because there may be dependent limitations between fields or between parameters.
300     // TODO(hiroh): I have to fill the return value. Comments in C2Component.h doesn't mention
301     // about the return value when conflict happens. I set C2_BAD_VALUE to it temporarily now.
302     c2_status_t stConfig = mIntf->config_vb(params, C2_DONT_BLOCK, &failures);
303     if (stConfig == C2_OK) {
304         EXPECT_EQ(0u, failures.size());
305     } else {
306         ASSERT_EQ(C2_BAD_VALUE, stConfig);
307         EXPECT_EQ(1u, failures.size());
308         EXPECT_EQ(C2SettingResult::CONFLICT, failures[0]->failure);
309     }
310     *configResult = stConfig;
311 }
312 
313 template <typename T>
configWritableParamInvalidValue(const T & newParam)314 void C2CompIntfTest::configWritableParamInvalidValue(const T &newParam) {
315     std::unique_ptr<T> p = makeParamFrom(newParam);
316 
317     std::vector<C2Param*> params{p.get()};
318     std::vector<std::unique_ptr<C2SettingResult>> failures;
319     // Although a parameter is writable, config_vb should be failed,
320     // because a new value is invalid.
321     ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
322     ASSERT_EQ(1u, failures.size());
323     EXPECT_EQ(C2SettingResult::BAD_VALUE, failures[0]->failure);
324 }
325 
326 // There is only used enum type for the field type, that is C2DomainKind.
327 // If another field type is added, it is necessary to add function for that.
328 template <>
getTestValues(const C2FieldSupportedValues & validValueInfos,std::vector<C2DomainKind> * const validValues,std::vector<C2DomainKind> * const invalidValues)329 void C2CompIntfTest::getTestValues(
330         const C2FieldSupportedValues &validValueInfos,
331         std::vector<C2DomainKind> *const validValues,
332         std::vector<C2DomainKind> *const invalidValues) {
333     UNUSED(validValueInfos);
334     validValues->emplace_back(C2DomainVideo);
335     validValues->emplace_back(C2DomainAudio);
336     validValues->emplace_back(C2DomainOther);
337 
338     // There is no invalid value.
339     UNUSED(invalidValues);
340 }
341 
342 template <typename TField>
getTestValues(const C2FieldSupportedValues & validValueInfos,std::vector<TField> * const validValues,std::vector<TField> * const invalidValues)343 void C2CompIntfTest::getTestValues(
344         const C2FieldSupportedValues &validValueInfos,
345         std::vector<TField> *const validValues,
346         std::vector<TField> *const invalidValues) {
347     using TStorage = typename _c2_reduce_enum_to_underlying_type<TField>::type;
348 
349     // The supported values are represented by C2Values. C2Value::Primitive needs to
350     // be transformed to a primitive value. This function is one to do that.
351     auto prim2Value = [](const C2Value::Primitive &prim) -> TField {
352         return (TField)prim.ref<TStorage>();
353         static_assert(std::is_same<TStorage, int32_t>::value ||
354                       std::is_same<TStorage, uint32_t>::value ||
355                       std::is_same<TStorage, int64_t>::value ||
356                       std::is_same<TStorage, uint64_t>::value ||
357                       std::is_same<TStorage, float>::value, "Invalid TField type.");
358     };
359 
360     // The size of validValueInfos is one.
361     const auto &c2FSV = validValueInfos;
362 
363     switch (c2FSV.type) {
364     case C2FieldSupportedValues::type_t::EMPTY: {
365         invalidValues->emplace_back(TField(0));
366         // TODO(hiroh) : Should other invalid values be tested?
367         break;
368     }
369     case C2FieldSupportedValues::type_t::RANGE: {
370         const auto &range = c2FSV.range;
371         auto rmin = prim2Value(range.min);
372         auto rmax = prim2Value(range.max);
373         auto rstep = prim2Value(range.step);
374 
375         ASSERT_LE(rmin, rmax);
376 
377         if (rstep != 0) {
378             // Increase linear
379             for (auto v = rmin; v <= rmax; v = TField(v + rstep)) {
380                 validValues->emplace_back(v);
381             }
382             if (rmin > std::numeric_limits<TField>::min()) {
383                 invalidValues->emplace_back(TField(rmin - 1));
384             }
385             if (rmax < std::numeric_limits<TField>::max()) {
386                 invalidValues->emplace_back(TField(rmax + 1));
387             }
388             const unsigned int N = validValues->size();
389             if (N >= 2) {
390                 if (std::is_same<TField, float>::value) {
391                     invalidValues->emplace_back(TField((validValues->at(0) + validValues->at(1)) / 2));
392                     invalidValues->emplace_back(TField((validValues->at(N - 2) + validValues->at(N - 1)) / 2));
393                 } else {
394                     if (rstep > 1) {
395                         invalidValues->emplace_back(TField(validValues->at(0) + 1));
396                         invalidValues->emplace_back(TField(validValues->at(N - 1) - 1));
397                     }
398                 }
399             }
400         } else {
401             // There should be two cases, except linear case.
402             // 1. integer geometric case
403             // 2. float geometric case
404 
405             auto num = prim2Value(range.num);
406             auto denom = prim2Value(range.denom);
407 
408             // If both range.num and range.denom are 1 and step is 0, we should use
409             // VALUES, shouldn't we?
410             ASSERT_FALSE(num == 1 && denom == 1);
411 
412             // (num / denom) is not less than 1.
413             ASSERT_FALSE(denom == 0);
414             ASSERT_LE(denom, num);
415             for (auto v = rmin; v <= rmax; v = TField(v * num / denom)) {
416                 validValues->emplace_back(v);
417             }
418 
419             if (rmin > std::numeric_limits<TField>::min()) {
420                 invalidValues->emplace_back(TField(rmin - 1));
421             }
422             if (rmax < std::numeric_limits<TField>::max()) {
423                 invalidValues->emplace_back(TField(rmax + 1));
424             }
425 
426             const unsigned int N = validValues->size();
427             if (N >= 2) {
428                 if (std::is_same<TField, float>::value) {
429                     invalidValues->emplace_back(TField((validValues->at(0) + validValues->at(1)) / 2));
430                     invalidValues->emplace_back(TField((validValues->at(N - 2) + validValues->at(N - 1)) / 2));
431                 } else {
432                     if (validValues->at(1) - validValues->at(0) > 1) {
433                         invalidValues->emplace_back(TField(validValues->at(0) + 1));
434                     }
435                     if (validValues->at(N - 1) - validValues->at(N - 2) > 1) {
436                         invalidValues->emplace_back(TField(validValues->at(N - 1) - 1));
437                     }
438                 }
439             }
440         }
441         break;
442     }
443     case C2FieldSupportedValues::type_t::VALUES: {
444         for (const C2Value::Primitive &prim : c2FSV.values) {
445             validValues->emplace_back(prim2Value(prim));
446         }
447         auto minv = *std::min_element(validValues->begin(), validValues->end());
448         auto maxv = *std::max_element(validValues->begin(), validValues->end());
449         if (minv - 1 > std::numeric_limits<TField>::min()) {
450             invalidValues->emplace_back(TField(minv - 1));
451         }
452         if (maxv + 1 < std::numeric_limits<TField>::max()) {
453             invalidValues->emplace_back(TField(maxv + 1));
454         }
455         break;
456     }
457     case C2FieldSupportedValues::type_t::FLAGS: {
458         // TODO(hiroh) : Implement the case that param.type is FLAGS.
459         break;
460     }
461     }
462 }
463 
464 template <typename T>
testReadOnlyParam(const T & preParam,const T & newParam)465 void C2CompIntfTest::testReadOnlyParam(const T &preParam, const T &newParam) {
466     TRACED_FAILURE(configReadOnlyParam(newParam));
467     // Parameter value must not be changed
468     TRACED_FAILURE(queryParamAsExpected(preParam));
469 }
470 
471 template <typename TParam, typename TRealField, typename TField>
testWritableParam(TParam * const param,TRealField * const writableField,const std::vector<TField> & validValues,const std::vector<TField> & invalidValues)472 void C2CompIntfTest::testWritableParam(
473         TParam *const param, TRealField *const writableField,
474         const std::vector<TField> &validValues,
475         const std::vector<TField> &invalidValues) {
476     c2_status_t stConfig;
477 
478     // Get the parameter's value in the beginning in order to reset the value at the end.
479     TRACED_FAILURE(getValue(param));
480     std::unique_ptr<TParam> defaultParam = makeParamFrom(*param);
481 
482     // Test valid values
483     for (const auto &val : validValues) {
484         std::unique_ptr<TParam> preParam = makeParamFrom(*param);
485 
486         // Param is try to be changed
487         *writableField = val;
488         TRACED_FAILURE(configWritableParamValidValue(*param, &stConfig));
489         if (stConfig == C2_OK) {
490             TRACED_FAILURE(queryParamAsExpected(*param));
491         } else {
492             // Param is unchanged because a field value conflicts with other field or parameter.
493             TRACED_FAILURE(queryParamAsExpected(*preParam));
494         }
495     }
496 
497     // Store the current parameter in order to test |param| is unchanged
498     // after trying to write an invalid value.
499     std::unique_ptr<TParam> lastValidParam = makeParamFrom(*param);
500 
501     // Test invalid values
502     for (const auto &val : invalidValues) {
503         // Param is changed
504         *writableField = val;
505         TRACED_FAILURE(configWritableParamInvalidValue(*param));
506         TRACED_FAILURE(queryParamAsExpected(*lastValidParam));
507     }
508     // Reset the parameter by config().
509     TRACED_FAILURE(configWritableParamValidValue(*defaultParam, &stConfig));
510 }
511 
testUnsupportedParam()512 template <typename T> void C2CompIntfTest::testUnsupportedParam() {
513     TRACED_FAILURE(queryUnsupportedParam<T>());
514 }
515 
testSupportedParam()516 template <typename T> void C2CompIntfTest::testSupportedParam() {
517     TRACED_FAILURE(querySupportedParam<T>());
518 }
519 
isSupportedParam(const C2Param & param,const std::vector<std::shared_ptr<C2ParamDescriptor>> & sParams)520 bool isSupportedParam(
521         const C2Param &param,
522         const std::vector<std::shared_ptr<C2ParamDescriptor>> &sParams) {
523     for (const auto &pd : sParams) {
524         if (param.type() == pd->index().type()) {
525             return true;
526         }
527     }
528     return false;
529 }
530 
531 template <typename T>
checkParamPermission(int * const result,const std::vector<std::shared_ptr<C2ParamDescriptor>> & supportedParams)532 void C2CompIntfTest::checkParamPermission(
533     int *const result,
534     const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams) {
535     std::unique_ptr<T> param = makeParam<T>();
536 
537     if (!isSupportedParam(*param, supportedParams)) {
538         // If a parameter isn't supported, it just finish after calling testUnsupportedParam().
539         testUnsupportedParam<T>();
540         *result = ParamPermission::UNSUPPORTED;
541         return;
542     }
543 
544     testSupportedParam<T>();
545 
546     TRACED_FAILURE(getValue(param.get()));
547     std::vector<std::unique_ptr<C2SettingResult>> failures;
548     // Config does not change the parameter, because param is the present param.
549     // This config is executed to find out if a parameter is read-only or writable.
550     c2_status_t stStack = config(param.get(), &failures);
551     if (stStack == C2_BAD_VALUE) {
552         // Read-only
553         std::unique_ptr<T> newParam = makeParam<T>();
554         testReadOnlyParam(*param, *newParam);
555         *result = ParamPermission::READONLY;
556     } else {
557         // Writable
558         EXPECT_EQ(stStack, C2_OK);
559         *result = ParamPermission::WRITABLE;
560     }
561 }
562 
outputResults(const std::string & name)563 void C2CompIntfTest::outputResults(const std::string &name) {
564     std::vector<std::string> params[3];
565     for (const auto &testInfo : mParamResults) {
566         int result = testInfo.result;
567         ASSERT_TRUE(0 <= result && result <= 2);
568         params[result].emplace_back(testInfo.name);
569     }
570     const char *resultString[] = {"Writable", "Read-Only", "Unsupported"};
571     printf("\n----TEST RESULTS (%s)----\n\n", name.c_str());
572     for (int i = 0; i < 3; i++) {
573         printf("[ %s ]\n", resultString[i]);
574         for (const auto &t : params[i]) {
575             printf("%s\n", t.c_str());
576         }
577         printf("\n");
578     }
579 }
580 
581 #define TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, field_name_) \
582     do {                                                                \
583         std::unique_ptr<TParam_> param = makeParam<TParam_>();          \
584         std::vector<C2FieldSupportedValuesQuery> validValueInfos = {    \
585             C2FieldSupportedValuesQuery::Current(                       \
586                     C2ParamField(param.get(), &field_type_name_::field_name_)) \
587         };                                                              \
588         ASSERT_EQ(C2_OK,                                                \
589                   mIntf->querySupportedValues_vb(validValueInfos, C2_DONT_BLOCK));     \
590         ASSERT_EQ(1u, validValueInfos.size());                          \
591         std::vector<decltype(param->field_name_)> validValues;          \
592         std::vector<decltype(param->field_name_)> invalidValues;        \
593         getTestValues(validValueInfos[0].values, &validValues, &invalidValues);   \
594         testWritableParam(param.get(), &param->field_name_, validValues,\
595                           invalidValues);                               \
596     } while (0)
597 
598 #define TEST_VSSTRUCT_WRITABLE_FIELD(TParam_, field_type_name_)         \
599     do {                                                                \
600         TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, width);  \
601         TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, height); \
602     } while (0)
603 
604 #define TEST_U32_WRITABLE_FIELD(TParam_, field_type_name_)              \
605   TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
606 
607 #define TEST_ENUM_WRITABLE_FIELD(TParam_, field_type_name_)             \
608   TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
609 
610 // TODO(hiroh): Support parameters based on char[] and uint32_t[].
611 //#define TEST_STRING_WRITABLE_FIELD(TParam_, field_type_name_)
612 // TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, m.value)
613 //#define TEST_U32ARRAY_WRITABLE_FIELD(Tparam_, field_type_name_)
614 // TEST_GENERAL_WRITABLE_FIELD(Tparam_, uint32_t[], field_type_name_, values)
615 
616 #define EACH_TEST(TParam_, field_type_name_, test_name)                 \
617     do {                                                                \
618       int result = 0;                                                   \
619       this->mCurrentParamName = #TParam_;                            \
620       checkParamPermission<TParam_>(&result, supportedParams);          \
621       if (result == ParamPermission::WRITABLE) {                        \
622           test_name(TParam_, field_type_name_);                         \
623       }                                                                 \
624       mParamResults.emplace_back(#TParam_, result);                      \
625   } while (0)
626 
627 #define EACH_TEST_SELF(type_, test_name) EACH_TEST(type_, type_, test_name)
628 #define EACH_TEST_INPUT(type_, test_name) EACH_TEST(type_::input, type_, test_name)
629 #define EACH_TEST_OUTPUT(type_, test_name) EACH_TEST(type_::output, type_, test_name)
testMain(std::shared_ptr<C2ComponentInterface> intf,const std::string & componentName)630 void C2CompIntfTest::testMain(std::shared_ptr<C2ComponentInterface> intf,
631                               const std::string &componentName) {
632     setComponent(intf);
633 
634     std::vector<std::shared_ptr<C2ParamDescriptor>> supportedParams;
635     ASSERT_EQ(C2_OK, mIntf->querySupportedParams_nb(&supportedParams));
636 
637     EACH_TEST_SELF(C2ComponentLatencyInfo, TEST_U32_WRITABLE_FIELD);
638     EACH_TEST_SELF(C2ComponentTemporalInfo, TEST_U32_WRITABLE_FIELD);
639     EACH_TEST_INPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
640     EACH_TEST_OUTPUT(C2PortLatencyInfo, TEST_U32_WRITABLE_FIELD);
641     EACH_TEST_INPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
642     EACH_TEST_OUTPUT(C2StreamFormatConfig, TEST_U32_WRITABLE_FIELD);
643     EACH_TEST_INPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
644     EACH_TEST_OUTPUT(C2PortStreamCountConfig, TEST_U32_WRITABLE_FIELD);
645 
646     EACH_TEST_SELF(C2ComponentDomainInfo, TEST_ENUM_WRITABLE_FIELD);
647 
648     // TODO(hiroh): Support parameters based on uint32_t[] and char[].
649     // EACH_TEST_INPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
650     // EACH_TEST_OUTPUT(C2PortMimeConfig, TEST_STRING_WRITABLE_FIELD);
651     // EACH_TEST_INPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
652     // EACH_TEST_OUTPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
653 
654     // EACH_TEST_SELF(C2SupportedParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
655     // EACH_TEST_SELF(C2RequiredParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
656     // EACH_TEST_SELF(C2ReadOnlyParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
657     // EACH_TEST_SELF(C2RequestedInfosInfo, TEST_U32ARRAY_WRITABLE_FIELD);
658 
659     EACH_TEST_INPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
660     EACH_TEST_OUTPUT(C2VideoSizeStreamInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
661     EACH_TEST_INPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
662     EACH_TEST_OUTPUT(C2VideoSizeStreamTuning, TEST_VSSTRUCT_WRITABLE_FIELD);
663     EACH_TEST_INPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
664     EACH_TEST_OUTPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
665 
666     outputResults(componentName);
667     resetResults();
668 }
669 
TEST_F(C2CompIntfTest,C2V4L2CodecIntf)670 TEST_F(C2CompIntfTest, C2V4L2CodecIntf) {
671 
672     // Read a shared object library.
673     void* compLib = dlopen("system/lib/libv4l2_codec2.so", RTLD_NOW);
674 
675     if (!compLib) {
676         printf("Cannot open library: %s.\n", dlerror());
677         FAIL();
678         return;
679     }
680 
681     typedef C2ComponentStore* create_t();
682     create_t* create_store= (create_t*) dlsym(compLib, "create_store");
683     const char* dlsym_error = dlerror();
684     if (dlsym_error) {
685         printf("Cannot load symbol create: %s.\n", dlsym_error);
686         FAIL();
687         return;
688     }
689 
690     typedef void destroy_t(C2ComponentStore*);
691     destroy_t* destroy_store = (destroy_t*) dlsym(compLib, "destroy_store");
692     dlsym_error = dlerror();
693     if (dlsym_error) {
694         printf("Cannot load symbol destroy: %s.\n", dlsym_error);
695         FAIL();
696         return;
697     }
698 
699     std::shared_ptr<C2ComponentStore> componentStore(create_store(), destroy_store);
700     std::shared_ptr<C2ComponentInterface> componentIntf;
701     componentStore->createInterface("v4l2.decoder", &componentIntf);
702     auto componentName = "C2V4L2Codec";
703     testMain(componentIntf, componentName);
704 }
705 
706 } // namespace android
707