Home | History | Annotate | Download | only in tests
      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 
     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:
     49     C2CompIntfTest() {}
     50     ~C2CompIntfTest() override {}
     51 
     52     void setComponent(std::shared_ptr<C2ComponentInterface> intf) {
     53         mIntf = intf;
     54     }
     55 
     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;
    109         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.
    181 template <typename T> std::unique_ptr<T> makeParam() {
    182     return std::make_unique<T>();
    183 }
    184 
    185 template <> std::unique_ptr<C2PortMediaTypeSetting::input> makeParam() {
    186     // TODO(hiroh): Set more precise length.
    187     return C2PortMediaTypeSetting::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 
    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>
    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 
    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>
    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 
    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 
    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>
    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|.
    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>
    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>
    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>
    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 C2Component::domain_t.
    327 // If another field type is added, it is necessary to add function for that.
    328 template <>
    329 void C2CompIntfTest::getTestValues(
    330         const C2FieldSupportedValues &validValueInfos,
    331         std::vector<C2Component::domain_t> *const validValues,
    332         std::vector<C2Component::domain_t> *const invalidValues) {
    333     UNUSED(validValueInfos);
    334     validValues->emplace_back(C2Component::DOMAIN_VIDEO);
    335     validValues->emplace_back(C2Component::DOMAIN_AUDIO);
    336     validValues->emplace_back(C2Component::DOMAIN_OTHER);
    337 
    338     // There is no invalid value.
    339     UNUSED(invalidValues);
    340 }
    341 
    342 template <typename TField>
    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>
    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>
    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 
    512 template <typename T> void C2CompIntfTest::testUnsupportedParam() {
    513     TRACED_FAILURE(queryUnsupportedParam<T>());
    514 }
    515 
    516 template <typename T> void C2CompIntfTest::testSupportedParam() {
    517     TRACED_FAILURE(querySupportedParam<T>());
    518 }
    519 
    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>
    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 
    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)
    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(C2ActualPipelineDelayTuning, TEST_U32_WRITABLE_FIELD);
    638     EACH_TEST_SELF(C2ComponentAttributesSetting, TEST_U32_WRITABLE_FIELD);
    639     EACH_TEST_INPUT(C2PortActualDelayTuning, TEST_U32_WRITABLE_FIELD);
    640     EACH_TEST_OUTPUT(C2PortActualDelayTuning, TEST_U32_WRITABLE_FIELD);
    641     EACH_TEST_INPUT(C2StreamBufferTypeSetting, TEST_U32_WRITABLE_FIELD);
    642     EACH_TEST_OUTPUT(C2StreamBufferTypeSetting, TEST_U32_WRITABLE_FIELD);
    643     EACH_TEST_INPUT(C2PortStreamCountTuning, TEST_U32_WRITABLE_FIELD);
    644     EACH_TEST_OUTPUT(C2PortStreamCountTuning, TEST_U32_WRITABLE_FIELD);
    645 
    646     EACH_TEST_SELF(C2ComponentDomainSetting, TEST_ENUM_WRITABLE_FIELD);
    647 
    648     // TODO(hiroh): Support parameters based on uint32_t[] and char[].
    649     // EACH_TEST_INPUT(C2PortMediaTypeSetting, TEST_STRING_WRITABLE_FIELD);
    650     // EACH_TEST_OUTPUT(C2PortMediaTypeSetting, 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(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
    660     EACH_TEST_OUTPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
    661     EACH_TEST_INPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
    662     EACH_TEST_OUTPUT(C2StreamPictureSizeInfo, 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 
    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