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
38namespace android {
39
40template <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
47class C2CompIntfTest : public ::testing::Test {
48protected:
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
99private:
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.
181template <typename T> std::unique_ptr<T> makeParam() {
182    return std::make_unique<T>();
183}
184
185template <> 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
199template <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
204template <typename T>
205c2_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
214template <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
219template <typename T>
220void 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
241template <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
248template <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
262template <typename T>
263c2_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|.
270template <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
277template <typename T>
278void 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
290template <typename T>
291void 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
313template <typename T>
314void 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.
328template <>
329void 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
342template <typename TField>
343void 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
464template <typename T>
465void 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
471template <typename TParam, typename TRealField, typename TField>
472void 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
512template <typename T> void C2CompIntfTest::testUnsupportedParam() {
513    TRACED_FAILURE(queryUnsupportedParam<T>());
514}
515
516template <typename T> void C2CompIntfTest::testSupportedParam() {
517    TRACED_FAILURE(querySupportedParam<T>());
518}
519
520bool 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
531template <typename T>
532void 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
563void 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)
630void 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
670TEST_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