You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
707 lines
29 KiB
707 lines
29 KiB
/*
|
|
* Copyright 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "C2ComponentInterface_test"
|
|
|
|
#include <dlfcn.h>
|
|
#include <stdio.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <utils/Log.h>
|
|
|
|
#include <C2Component.h>
|
|
#include <C2Config.h>
|
|
#include <util/C2InterfaceHelper.h>
|
|
#include <C2Param.h>
|
|
|
|
#if !defined(UNUSED)
|
|
#define UNUSED(expr) \
|
|
do { \
|
|
(void)(expr); \
|
|
} while (0)
|
|
|
|
#endif //!defined(UNUSED)
|
|
|
|
namespace android {
|
|
|
|
template <class T> std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
|
|
size_t len = strlen(cstr);
|
|
std::unique_ptr<T> ptr = T::AllocUnique(len);
|
|
memcpy(ptr->m.value, cstr, len);
|
|
return ptr;
|
|
}
|
|
|
|
class C2CompIntfTest : public ::testing::Test {
|
|
protected:
|
|
C2CompIntfTest() {}
|
|
~C2CompIntfTest() override {}
|
|
|
|
void setComponent(std::shared_ptr<C2ComponentInterface> intf) {
|
|
mIntf = intf;
|
|
}
|
|
|
|
void resetResults() {
|
|
mIntf = nullptr;
|
|
mParamResults.clear();
|
|
}
|
|
|
|
template <typename T> void testUnsupportedParam();
|
|
|
|
template <typename T> void testSupportedParam();
|
|
|
|
// testReadOnlyParam() and testWritableParam() are the main functions for testing a parameter.
|
|
// A caller should find out if a tested parameter is read-only or writable before calling them
|
|
// and it must call one of the corresponded them.
|
|
|
|
// If a parameter is read-only this is called.
|
|
// Test read-only parameter |preParam|. The test expects failure while config() with |newParam|,
|
|
// and make sure |preParam| stay unchanged.
|
|
template <typename T>
|
|
void testReadOnlyParam(const T &preParam, const T &newParam);
|
|
|
|
// If a parameter is writable this is called.
|
|
// Test one filed |writableField| for given writable parameter |param|.
|
|
// |validValues| contains all values obtained from querySupportedValues() for |writableField|.
|
|
// The test checks validity for config() with each value, and make sure values are config-ed
|
|
// by query() them out. |invalidValues| contains some values which are not in |validValues|.
|
|
// The test expects C2_BAD_VALUE while config() with these values,
|
|
// and |param| should stay unchanged.
|
|
template <typename TParam, typename TRealField, typename TField>
|
|
void testWritableParam(TParam *const param, TRealField *const writableField,
|
|
const std::vector<TField> &validValues,
|
|
const std::vector<TField> &invalidValues);
|
|
|
|
// Test all the defined parameters in C2Param.h.
|
|
void testMain(std::shared_ptr<C2ComponentInterface> intf,
|
|
const std::string &componentName);
|
|
|
|
// Check permission of parameter type |T| for testing interface.
|
|
// This should be called first of the testing per parameter type,
|
|
// therefore different testing process is applied according to the permission type.
|
|
template <typename T>
|
|
void checkParamPermission(
|
|
int *const writable,
|
|
const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams);
|
|
|
|
private:
|
|
enum ParamPermission : int {
|
|
WRITABLE,
|
|
READONLY,
|
|
UNSUPPORTED,
|
|
};
|
|
|
|
struct paramTestInfo {
|
|
std::string name;
|
|
int result;
|
|
paramTestInfo(const char *name_, int result_)
|
|
: name(name_), result(result_) {}
|
|
};
|
|
|
|
// queryOnStack() and queryonHeap() both call an interface's query_vb() and
|
|
// check if a component has a parameter whose type is |T|.
|
|
// If a component has, the value should be copied into an argument, that is
|
|
// |p| in queryOnStack() and |heapParams| in queryOnHeap().
|
|
// The return value is c2_status_t (e.g. C2_OK).
|
|
template <typename T> c2_status_t queryOnStack(T *const p);
|
|
|
|
template <typename T>
|
|
c2_status_t queryOnHeap(const T &p,
|
|
std::vector<std::unique_ptr<C2Param>> *const heapParams);
|
|
|
|
// Get a value whose type is |T| in a component. The value is copied to |param|.
|
|
// This should be called only if a component has the parameter.
|
|
template <typename T> void getValue(T *const param);
|
|
|
|
// Check if the parameter's value in component is equal to |expected| and
|
|
// queryOnStack() and queryOnHeap() are succeeded. When this function called,
|
|
// it should be guaranteed a component has the parameter.
|
|
template <typename T> void queryParamAsExpected(const T &expected);
|
|
|
|
// Test if query functions works correctly for supported parameters.
|
|
// "Support" means here a component has the parameter.
|
|
template <typename T> void querySupportedParam();
|
|
|
|
// Test query functions works correctly for unsupported parameters.
|
|
// "Unsupport" means here a component doesn't have the parameter.
|
|
template <typename T> void queryUnsupportedParam();
|
|
|
|
// Execute an interface's config_vb(). |T| is a single parameter type, not std::vector.
|
|
// config() creates std::vector<C2Param *> {p} and passes it to config_vb().
|
|
template <typename T>
|
|
c2_status_t
|
|
config(T *const p,
|
|
std::vector<std::unique_ptr<C2SettingResult>> *const failures);
|
|
|
|
// Test if config works correctly for read-only parameters.
|
|
// Because the failure of config() is assumed, |newParam| doesn't matter.
|
|
template <typename T> void configReadOnlyParam(const T &newParam);
|
|
|
|
// Test if config works correctly for writable parameters.
|
|
// This changes the parameter's value to |newParam|.
|
|
// |stConfig| is a return value of config().
|
|
template <typename T> void configWritableParamValidValue(const T &newParam, c2_status_t *stConfig);
|
|
|
|
// Test if config works correctly in the case an invalid value |newParam| is tried to write
|
|
// to an writable parameter.
|
|
template <typename T> void configWritableParamInvalidValue(const T &newParam);
|
|
|
|
// Create values for testing from |validValueInfos|. The values are returned as arguments.
|
|
// |validValues| : valid values, which can be written for the parameter.
|
|
// |InvalidValues| : invalid values, which cannot be written for the parameter.
|
|
// config() should be failed if these values are used as new values.
|
|
// This function should be called only for writable and supported parameters.
|
|
template <typename TField>
|
|
void getTestValues(const C2FieldSupportedValues &validValueInfos,
|
|
std::vector<TField> *const validValues,
|
|
std::vector<TField> *const invalidValues);
|
|
|
|
// Output the summary of test results. Categorizes parameters with their configuration.
|
|
void outputResults(const std::string &name);
|
|
|
|
std::shared_ptr<C2ComponentInterface> mIntf;
|
|
std::vector<paramTestInfo> mParamResults;
|
|
std::string mCurrentParamName;
|
|
};
|
|
|
|
// factory function
|
|
// TODO(hiroh): Add factory functions for other types.
|
|
template <typename T> std::unique_ptr<T> makeParam() {
|
|
return std::make_unique<T>();
|
|
}
|
|
|
|
template <> std::unique_ptr<C2PortMediaTypeSetting::input> makeParam() {
|
|
// TODO(hiroh): Set more precise length.
|
|
return C2PortMediaTypeSetting::input::AllocUnique(100);
|
|
}
|
|
|
|
#define TRACED_FAILURE(func) \
|
|
do { \
|
|
SCOPED_TRACE(mCurrentParamName); \
|
|
func; \
|
|
if (::testing::Test::HasFatalFailure()) { \
|
|
return; \
|
|
} \
|
|
} while (false)
|
|
|
|
template <typename T> c2_status_t C2CompIntfTest::queryOnStack(T *const p) {
|
|
std::vector<C2Param*> stackParams{p};
|
|
return mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr);
|
|
}
|
|
|
|
template <typename T>
|
|
c2_status_t C2CompIntfTest::queryOnHeap(
|
|
const T &p, std::vector<std::unique_ptr<C2Param>> *const heapParams) {
|
|
uint32_t index = p.index() & ~0x03FE0000;
|
|
if (p.forStream()) {
|
|
index |= ((p.stream() << 17) & 0x01FE0000) | 0x02000000;
|
|
}
|
|
return mIntf->query_vb({}, {index}, C2_DONT_BLOCK, heapParams);
|
|
}
|
|
|
|
template <typename T> void C2CompIntfTest::getValue(T *const param) {
|
|
// When getValue() is called, a component has to have the parameter.
|
|
ASSERT_EQ(C2_OK, queryOnStack(param));
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::queryParamAsExpected(const T &expected) {
|
|
// TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
|
|
// Note that all the current supported parameters are non-flex params.
|
|
T stack;
|
|
std::unique_ptr<T> pHeap = makeParam<T>();
|
|
std::vector<std::unique_ptr<C2Param>> heapParams;
|
|
|
|
ASSERT_EQ(C2_OK, queryOnStack(&stack));
|
|
|
|
// |stack| is a parameter value. The parameter size shouldn't be 0.
|
|
EXPECT_NE(0u, stack.size());
|
|
EXPECT_EQ(stack, expected);
|
|
|
|
ASSERT_EQ(C2_OK, queryOnHeap(*pHeap, &heapParams));
|
|
|
|
// |*heapParams[0]| is a parameter value. The size of |heapParams| has to be one.
|
|
ASSERT_EQ(1u, heapParams.size());
|
|
EXPECT_TRUE(heapParams[0]);
|
|
EXPECT_EQ(*heapParams[0], expected);
|
|
}
|
|
|
|
template <typename T> void C2CompIntfTest::querySupportedParam() {
|
|
std::unique_ptr<T> param = makeParam<T>();
|
|
// The current parameter's value is acquired by getValue(), which should be succeeded.
|
|
getValue(param.get());
|
|
queryParamAsExpected(*param);
|
|
}
|
|
|
|
template <typename T> void C2CompIntfTest::queryUnsupportedParam() {
|
|
// TODO(hiroh): Don't create param on stack and call queryOnStack for flex params.
|
|
// Note that all the current supported parameters are non-flex params.
|
|
T stack;
|
|
std::unique_ptr<T> pHeap = makeParam<T>();
|
|
std::vector<std::unique_ptr<C2Param>> heapParams;
|
|
// If a component doesn't have the parameter, queryOnStack() and queryOnHeap()
|
|
// should return C2_BAD_INDEX.
|
|
ASSERT_EQ(C2_BAD_INDEX, queryOnStack(&stack));
|
|
EXPECT_FALSE(stack);
|
|
ASSERT_EQ(C2_BAD_INDEX, queryOnHeap(*pHeap, &heapParams));
|
|
EXPECT_EQ(0u, heapParams.size());
|
|
}
|
|
|
|
template <typename T>
|
|
c2_status_t C2CompIntfTest::config(
|
|
T *const p, std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
|
|
std::vector<C2Param*> params{p};
|
|
return mIntf->config_vb(params, C2_DONT_BLOCK, failures);
|
|
}
|
|
|
|
// Create a new parameter copied from |p|.
|
|
template <typename T> std::unique_ptr<T> makeParamFrom(const T &p) {
|
|
std::unique_ptr<T> retP = makeParam<T>();
|
|
EXPECT_TRUE(retP->updateFrom(p));
|
|
EXPECT_TRUE(memcmp(retP.get(), &p, sizeof(T)) == 0);
|
|
return retP;
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::configReadOnlyParam(const T &newParam) {
|
|
std::unique_ptr<T> p = makeParamFrom(newParam);
|
|
|
|
std::vector<C2Param*> params{p.get()};
|
|
std::vector<std::unique_ptr<C2SettingResult>> failures;
|
|
|
|
// config_vb should be failed because a parameter is read-only.
|
|
ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
|
|
ASSERT_EQ(1u, failures.size());
|
|
EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure);
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::configWritableParamValidValue(const T &newParam, c2_status_t *configResult) {
|
|
std::unique_ptr<T> p = makeParamFrom(newParam);
|
|
|
|
std::vector<C2Param*> params{p.get()};
|
|
std::vector<std::unique_ptr<C2SettingResult>> failures;
|
|
// In most cases, config_vb return C2_OK and the parameter's value should be changed
|
|
// to |newParam|, which is confirmed in a caller of configWritableParamValueValue().
|
|
// However, this can return ~~~~ and the parameter's values is not changed,
|
|
// because there may be dependent limitations between fields or between parameters.
|
|
// TODO(hiroh): I have to fill the return value. Comments in C2Component.h doesn't mention
|
|
// about the return value when conflict happens. I set C2_BAD_VALUE to it temporarily now.
|
|
c2_status_t stConfig = mIntf->config_vb(params, C2_DONT_BLOCK, &failures);
|
|
if (stConfig == C2_OK) {
|
|
EXPECT_EQ(0u, failures.size());
|
|
} else {
|
|
ASSERT_EQ(C2_BAD_VALUE, stConfig);
|
|
EXPECT_EQ(1u, failures.size());
|
|
EXPECT_EQ(C2SettingResult::CONFLICT, failures[0]->failure);
|
|
}
|
|
*configResult = stConfig;
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::configWritableParamInvalidValue(const T &newParam) {
|
|
std::unique_ptr<T> p = makeParamFrom(newParam);
|
|
|
|
std::vector<C2Param*> params{p.get()};
|
|
std::vector<std::unique_ptr<C2SettingResult>> failures;
|
|
// Although a parameter is writable, config_vb should be failed,
|
|
// because a new value is invalid.
|
|
ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures));
|
|
ASSERT_EQ(1u, failures.size());
|
|
EXPECT_EQ(C2SettingResult::BAD_VALUE, failures[0]->failure);
|
|
}
|
|
|
|
// There is only used enum type for the field type, that is C2Component::domain_t.
|
|
// If another field type is added, it is necessary to add function for that.
|
|
template <>
|
|
void C2CompIntfTest::getTestValues(
|
|
const C2FieldSupportedValues &validValueInfos,
|
|
std::vector<C2Component::domain_t> *const validValues,
|
|
std::vector<C2Component::domain_t> *const invalidValues) {
|
|
UNUSED(validValueInfos);
|
|
validValues->emplace_back(C2Component::DOMAIN_VIDEO);
|
|
validValues->emplace_back(C2Component::DOMAIN_AUDIO);
|
|
validValues->emplace_back(C2Component::DOMAIN_OTHER);
|
|
|
|
// There is no invalid value.
|
|
UNUSED(invalidValues);
|
|
}
|
|
|
|
template <typename TField>
|
|
void C2CompIntfTest::getTestValues(
|
|
const C2FieldSupportedValues &validValueInfos,
|
|
std::vector<TField> *const validValues,
|
|
std::vector<TField> *const invalidValues) {
|
|
using TStorage = typename _c2_reduce_enum_to_underlying_type<TField>::type;
|
|
|
|
// The supported values are represented by C2Values. C2Value::Primitive needs to
|
|
// be transformed to a primitive value. This function is one to do that.
|
|
auto prim2Value = [](const C2Value::Primitive &prim) -> TField {
|
|
return (TField)prim.ref<TStorage>();
|
|
static_assert(std::is_same<TStorage, int32_t>::value ||
|
|
std::is_same<TStorage, uint32_t>::value ||
|
|
std::is_same<TStorage, int64_t>::value ||
|
|
std::is_same<TStorage, uint64_t>::value ||
|
|
std::is_same<TStorage, float>::value, "Invalid TField type.");
|
|
};
|
|
|
|
// The size of validValueInfos is one.
|
|
const auto &c2FSV = validValueInfos;
|
|
|
|
switch (c2FSV.type) {
|
|
case C2FieldSupportedValues::type_t::EMPTY: {
|
|
invalidValues->emplace_back(TField(0));
|
|
// TODO(hiroh) : Should other invalid values be tested?
|
|
break;
|
|
}
|
|
case C2FieldSupportedValues::type_t::RANGE: {
|
|
const auto &range = c2FSV.range;
|
|
auto rmin = prim2Value(range.min);
|
|
auto rmax = prim2Value(range.max);
|
|
auto rstep = prim2Value(range.step);
|
|
|
|
ASSERT_LE(rmin, rmax);
|
|
|
|
if (rstep != 0) {
|
|
// Increase linear
|
|
for (auto v = rmin; v <= rmax; v = TField(v + rstep)) {
|
|
validValues->emplace_back(v);
|
|
}
|
|
if (rmin > std::numeric_limits<TField>::min()) {
|
|
invalidValues->emplace_back(TField(rmin - 1));
|
|
}
|
|
if (rmax < std::numeric_limits<TField>::max()) {
|
|
invalidValues->emplace_back(TField(rmax + 1));
|
|
}
|
|
const unsigned int N = validValues->size();
|
|
if (N >= 2) {
|
|
if (std::is_same<TField, float>::value) {
|
|
invalidValues->emplace_back(TField((validValues->at(0) + validValues->at(1)) / 2));
|
|
invalidValues->emplace_back(TField((validValues->at(N - 2) + validValues->at(N - 1)) / 2));
|
|
} else {
|
|
if (rstep > 1) {
|
|
invalidValues->emplace_back(TField(validValues->at(0) + 1));
|
|
invalidValues->emplace_back(TField(validValues->at(N - 1) - 1));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// There should be two cases, except linear case.
|
|
// 1. integer geometric case
|
|
// 2. float geometric case
|
|
|
|
auto num = prim2Value(range.num);
|
|
auto denom = prim2Value(range.denom);
|
|
|
|
// If both range.num and range.denom are 1 and step is 0, we should use
|
|
// VALUES, shouldn't we?
|
|
ASSERT_FALSE(num == 1 && denom == 1);
|
|
|
|
// (num / denom) is not less than 1.
|
|
ASSERT_FALSE(denom == 0);
|
|
ASSERT_LE(denom, num);
|
|
for (auto v = rmin; v <= rmax; v = TField(v * num / denom)) {
|
|
validValues->emplace_back(v);
|
|
}
|
|
|
|
if (rmin > std::numeric_limits<TField>::min()) {
|
|
invalidValues->emplace_back(TField(rmin - 1));
|
|
}
|
|
if (rmax < std::numeric_limits<TField>::max()) {
|
|
invalidValues->emplace_back(TField(rmax + 1));
|
|
}
|
|
|
|
const unsigned int N = validValues->size();
|
|
if (N >= 2) {
|
|
if (std::is_same<TField, float>::value) {
|
|
invalidValues->emplace_back(TField((validValues->at(0) + validValues->at(1)) / 2));
|
|
invalidValues->emplace_back(TField((validValues->at(N - 2) + validValues->at(N - 1)) / 2));
|
|
} else {
|
|
if (validValues->at(1) - validValues->at(0) > 1) {
|
|
invalidValues->emplace_back(TField(validValues->at(0) + 1));
|
|
}
|
|
if (validValues->at(N - 1) - validValues->at(N - 2) > 1) {
|
|
invalidValues->emplace_back(TField(validValues->at(N - 1) - 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case C2FieldSupportedValues::type_t::VALUES: {
|
|
for (const C2Value::Primitive &prim : c2FSV.values) {
|
|
validValues->emplace_back(prim2Value(prim));
|
|
}
|
|
auto minv = *std::min_element(validValues->begin(), validValues->end());
|
|
auto maxv = *std::max_element(validValues->begin(), validValues->end());
|
|
if (minv - 1 > std::numeric_limits<TField>::min()) {
|
|
invalidValues->emplace_back(TField(minv - 1));
|
|
}
|
|
if (maxv + 1 < std::numeric_limits<TField>::max()) {
|
|
invalidValues->emplace_back(TField(maxv + 1));
|
|
}
|
|
break;
|
|
}
|
|
case C2FieldSupportedValues::type_t::FLAGS: {
|
|
// TODO(hiroh) : Implement the case that param.type is FLAGS.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::testReadOnlyParam(const T &preParam, const T &newParam) {
|
|
TRACED_FAILURE(configReadOnlyParam(newParam));
|
|
// Parameter value must not be changed
|
|
TRACED_FAILURE(queryParamAsExpected(preParam));
|
|
}
|
|
|
|
template <typename TParam, typename TRealField, typename TField>
|
|
void C2CompIntfTest::testWritableParam(
|
|
TParam *const param, TRealField *const writableField,
|
|
const std::vector<TField> &validValues,
|
|
const std::vector<TField> &invalidValues) {
|
|
c2_status_t stConfig;
|
|
|
|
// Get the parameter's value in the beginning in order to reset the value at the end.
|
|
TRACED_FAILURE(getValue(param));
|
|
std::unique_ptr<TParam> defaultParam = makeParamFrom(*param);
|
|
|
|
// Test valid values
|
|
for (const auto &val : validValues) {
|
|
std::unique_ptr<TParam> preParam = makeParamFrom(*param);
|
|
|
|
// Param is try to be changed
|
|
*writableField = val;
|
|
TRACED_FAILURE(configWritableParamValidValue(*param, &stConfig));
|
|
if (stConfig == C2_OK) {
|
|
TRACED_FAILURE(queryParamAsExpected(*param));
|
|
} else {
|
|
// Param is unchanged because a field value conflicts with other field or parameter.
|
|
TRACED_FAILURE(queryParamAsExpected(*preParam));
|
|
}
|
|
}
|
|
|
|
// Store the current parameter in order to test |param| is unchanged
|
|
// after trying to write an invalid value.
|
|
std::unique_ptr<TParam> lastValidParam = makeParamFrom(*param);
|
|
|
|
// Test invalid values
|
|
for (const auto &val : invalidValues) {
|
|
// Param is changed
|
|
*writableField = val;
|
|
TRACED_FAILURE(configWritableParamInvalidValue(*param));
|
|
TRACED_FAILURE(queryParamAsExpected(*lastValidParam));
|
|
}
|
|
// Reset the parameter by config().
|
|
TRACED_FAILURE(configWritableParamValidValue(*defaultParam, &stConfig));
|
|
}
|
|
|
|
template <typename T> void C2CompIntfTest::testUnsupportedParam() {
|
|
TRACED_FAILURE(queryUnsupportedParam<T>());
|
|
}
|
|
|
|
template <typename T> void C2CompIntfTest::testSupportedParam() {
|
|
TRACED_FAILURE(querySupportedParam<T>());
|
|
}
|
|
|
|
bool isSupportedParam(
|
|
const C2Param ¶m,
|
|
const std::vector<std::shared_ptr<C2ParamDescriptor>> &sParams) {
|
|
for (const auto &pd : sParams) {
|
|
if (param.type() == pd->index().type()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
void C2CompIntfTest::checkParamPermission(
|
|
int *const result,
|
|
const std::vector<std::shared_ptr<C2ParamDescriptor>> &supportedParams) {
|
|
std::unique_ptr<T> param = makeParam<T>();
|
|
|
|
if (!isSupportedParam(*param, supportedParams)) {
|
|
// If a parameter isn't supported, it just finish after calling testUnsupportedParam().
|
|
testUnsupportedParam<T>();
|
|
*result = ParamPermission::UNSUPPORTED;
|
|
return;
|
|
}
|
|
|
|
testSupportedParam<T>();
|
|
|
|
TRACED_FAILURE(getValue(param.get()));
|
|
std::vector<std::unique_ptr<C2SettingResult>> failures;
|
|
// Config does not change the parameter, because param is the present param.
|
|
// This config is executed to find out if a parameter is read-only or writable.
|
|
c2_status_t stStack = config(param.get(), &failures);
|
|
if (stStack == C2_BAD_VALUE) {
|
|
// Read-only
|
|
std::unique_ptr<T> newParam = makeParam<T>();
|
|
testReadOnlyParam(*param, *newParam);
|
|
*result = ParamPermission::READONLY;
|
|
} else {
|
|
// Writable
|
|
EXPECT_EQ(stStack, C2_OK);
|
|
*result = ParamPermission::WRITABLE;
|
|
}
|
|
}
|
|
|
|
void C2CompIntfTest::outputResults(const std::string &name) {
|
|
std::vector<std::string> params[3];
|
|
for (const auto &testInfo : mParamResults) {
|
|
int result = testInfo.result;
|
|
ASSERT_TRUE(0 <= result && result <= 2);
|
|
params[result].emplace_back(testInfo.name);
|
|
}
|
|
const char *resultString[] = {"Writable", "Read-Only", "Unsupported"};
|
|
printf("\n----TEST RESULTS (%s)----\n\n", name.c_str());
|
|
for (int i = 0; i < 3; i++) {
|
|
printf("[ %s ]\n", resultString[i]);
|
|
for (const auto &t : params[i]) {
|
|
printf("%s\n", t.c_str());
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
#define TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, field_name_) \
|
|
do { \
|
|
std::unique_ptr<TParam_> param = makeParam<TParam_>(); \
|
|
std::vector<C2FieldSupportedValuesQuery> validValueInfos = { \
|
|
C2FieldSupportedValuesQuery::Current( \
|
|
C2ParamField(param.get(), &field_type_name_::field_name_)) \
|
|
}; \
|
|
ASSERT_EQ(C2_OK, \
|
|
mIntf->querySupportedValues_vb(validValueInfos, C2_DONT_BLOCK)); \
|
|
ASSERT_EQ(1u, validValueInfos.size()); \
|
|
std::vector<decltype(param->field_name_)> validValues; \
|
|
std::vector<decltype(param->field_name_)> invalidValues; \
|
|
getTestValues(validValueInfos[0].values, &validValues, &invalidValues); \
|
|
testWritableParam(param.get(), ¶m->field_name_, validValues,\
|
|
invalidValues); \
|
|
} while (0)
|
|
|
|
#define TEST_VSSTRUCT_WRITABLE_FIELD(TParam_, field_type_name_) \
|
|
do { \
|
|
TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, width); \
|
|
TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, height); \
|
|
} while (0)
|
|
|
|
#define TEST_U32_WRITABLE_FIELD(TParam_, field_type_name_) \
|
|
TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
|
|
|
|
#define TEST_ENUM_WRITABLE_FIELD(TParam_, field_type_name_) \
|
|
TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, value)
|
|
|
|
// TODO(hiroh): Support parameters based on char[] and uint32_t[].
|
|
//#define TEST_STRING_WRITABLE_FIELD(TParam_, field_type_name_)
|
|
// TEST_GENERAL_WRITABLE_FIELD(TParam_, field_type_name_, m.value)
|
|
//#define TEST_U32ARRAY_WRITABLE_FIELD(Tparam_, field_type_name_)
|
|
// TEST_GENERAL_WRITABLE_FIELD(Tparam_, uint32_t[], field_type_name_, values)
|
|
|
|
#define EACH_TEST(TParam_, field_type_name_, test_name) \
|
|
do { \
|
|
int result = 0; \
|
|
this->mCurrentParamName = #TParam_; \
|
|
checkParamPermission<TParam_>(&result, supportedParams); \
|
|
if (result == ParamPermission::WRITABLE) { \
|
|
test_name(TParam_, field_type_name_); \
|
|
} \
|
|
mParamResults.emplace_back(#TParam_, result); \
|
|
} while (0)
|
|
|
|
#define EACH_TEST_SELF(type_, test_name) EACH_TEST(type_, type_, test_name)
|
|
#define EACH_TEST_INPUT(type_, test_name) EACH_TEST(type_::input, type_, test_name)
|
|
#define EACH_TEST_OUTPUT(type_, test_name) EACH_TEST(type_::output, type_, test_name)
|
|
void C2CompIntfTest::testMain(std::shared_ptr<C2ComponentInterface> intf,
|
|
const std::string &componentName) {
|
|
setComponent(intf);
|
|
|
|
std::vector<std::shared_ptr<C2ParamDescriptor>> supportedParams;
|
|
ASSERT_EQ(C2_OK, mIntf->querySupportedParams_nb(&supportedParams));
|
|
|
|
EACH_TEST_SELF(C2ActualPipelineDelayTuning, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_SELF(C2ComponentAttributesSetting, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_INPUT(C2PortActualDelayTuning, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2PortActualDelayTuning, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_INPUT(C2StreamBufferTypeSetting, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2StreamBufferTypeSetting, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_INPUT(C2PortStreamCountTuning, TEST_U32_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2PortStreamCountTuning, TEST_U32_WRITABLE_FIELD);
|
|
|
|
EACH_TEST_SELF(C2ComponentDomainSetting, TEST_ENUM_WRITABLE_FIELD);
|
|
|
|
// TODO(hiroh): Support parameters based on uint32_t[] and char[].
|
|
// EACH_TEST_INPUT(C2PortMediaTypeSetting, TEST_STRING_WRITABLE_FIELD);
|
|
// EACH_TEST_OUTPUT(C2PortMediaTypeSetting, TEST_STRING_WRITABLE_FIELD);
|
|
// EACH_TEST_INPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
|
|
// EACH_TEST_OUTPUT(C2StreamMimeConfig, TEST_STRING_WRITABLE_FIELD);
|
|
|
|
// EACH_TEST_SELF(C2SupportedParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
|
|
// EACH_TEST_SELF(C2RequiredParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
|
|
// EACH_TEST_SELF(C2ReadOnlyParamsInfo, TEST_U32ARRAY_WRITABLE_FIELD);
|
|
// EACH_TEST_SELF(C2RequestedInfosInfo, TEST_U32ARRAY_WRITABLE_FIELD);
|
|
|
|
EACH_TEST_INPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
EACH_TEST_INPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2StreamPictureSizeInfo, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
EACH_TEST_INPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
EACH_TEST_OUTPUT(C2MaxVideoSizeHintPortSetting, TEST_VSSTRUCT_WRITABLE_FIELD);
|
|
|
|
outputResults(componentName);
|
|
resetResults();
|
|
}
|
|
|
|
TEST_F(C2CompIntfTest, C2V4L2CodecIntf) {
|
|
|
|
// Read a shared object library.
|
|
void* compLib = dlopen("system/lib/libv4l2_codec2.so", RTLD_NOW);
|
|
|
|
if (!compLib) {
|
|
printf("Cannot open library: %s.\n", dlerror());
|
|
FAIL();
|
|
return;
|
|
}
|
|
|
|
typedef C2ComponentStore* create_t();
|
|
create_t* create_store= (create_t*) dlsym(compLib, "create_store");
|
|
const char* dlsym_error = dlerror();
|
|
if (dlsym_error) {
|
|
printf("Cannot load symbol create: %s.\n", dlsym_error);
|
|
FAIL();
|
|
return;
|
|
}
|
|
|
|
typedef void destroy_t(C2ComponentStore*);
|
|
destroy_t* destroy_store = (destroy_t*) dlsym(compLib, "destroy_store");
|
|
dlsym_error = dlerror();
|
|
if (dlsym_error) {
|
|
printf("Cannot load symbol destroy: %s.\n", dlsym_error);
|
|
FAIL();
|
|
return;
|
|
}
|
|
|
|
std::shared_ptr<C2ComponentStore> componentStore(create_store(), destroy_store);
|
|
std::shared_ptr<C2ComponentInterface> componentIntf;
|
|
componentStore->createInterface("v4l2.decoder", &componentIntf);
|
|
auto componentName = "C2V4L2Codec";
|
|
testMain(componentIntf, componentName);
|
|
}
|
|
|
|
} // namespace android
|