| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef ANDROID_C2_COMPONENT_INTERFACE_TEST_H |
| #define ANDROID_C2_COMPONENT_INTERFACE_TEST_H |
| |
| #include <C2Config.h> |
| #include <C2PlatformSupport.h> |
| #include <util/C2InterfaceHelper.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include <inttypes.h> |
| #include <limits> |
| #include <memory> |
| |
| namespace android { |
| |
| class C2CompIntfTest : public ::testing::Test { |
| public: |
| void dumpParamDescriptions(); |
| |
| // The following codes are template implicit instantiations. These codes should not be separated |
| // into an individual cpp file from explicit specializations. Otherwise the compiler will fail |
| // to instantiate templates when the explicit specialization is present. |
| |
| template <typename T> |
| void testReadOnlyParam(const T* expected, T* invalid) { |
| testReadOnlyParamOnStack(expected, invalid); |
| testReadOnlyParamOnHeap(expected, invalid); |
| } |
| |
| template <typename T> |
| void checkReadOnlyFailureOnConfig(T* param) { |
| std::vector<C2Param*> params{param}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| |
| // TODO: do not assert on checking return value since it is not consistent for |
| // C2InterfaceHelper now. (b/79720928) |
| // 1) if config same value, it returns C2_OK |
| // 2) if config different value, it returns C2_CORRUPTED. But when you config again, it |
| // returns C2_OK |
| //ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| mIntf->config_vb(params, C2_DONT_BLOCK, &failures); |
| |
| // TODO: failure is not yet supported for C2InterfaceHelper |
| //ASSERT_EQ(1u, failures.size()); |
| //EXPECT_EQ(C2SettingResult::READ_ONLY, failures[0]->failure); |
| } |
| |
| // Note: this is not suitable for testing flex-type parameters. |
| template <typename T> |
| void testReadOnlyParamOnStack(const T* expected, T* invalid) { |
| T param; |
| std::vector<C2Param*> stackParams{¶m}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| EXPECT_EQ(*expected, param); |
| |
| checkReadOnlyFailureOnConfig(¶m); |
| checkReadOnlyFailureOnConfig(invalid); |
| |
| // The param must not change after failed config. |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| EXPECT_EQ(*expected, param); |
| } |
| |
| template <typename T> |
| void testReadOnlyParamOnHeap(const T* expected, T* invalid) { |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| |
| uint32_t index = expected->index(); |
| |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(*expected, *heapParams[0]); |
| |
| checkReadOnlyFailureOnConfig(heapParams[0].get()); |
| checkReadOnlyFailureOnConfig(invalid); |
| |
| // The param must not change after failed config. |
| heapParams.clear(); |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {index}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(*expected, *heapParams[0]); |
| } |
| |
| template <typename T> |
| void testWritableParam(T* newParam) { |
| std::vector<C2Param*> params{newParam}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| ASSERT_EQ(C2_OK, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(0u, failures.size()); |
| |
| // The param must change to newParam |
| // Check like param on stack |
| T param; |
| std::vector<C2Param*> stackParams{¶m}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| EXPECT_EQ(*newParam, param); |
| |
| // Check also like param on heap |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {newParam->index()}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(*newParam, *heapParams[0]); |
| } |
| |
| template <typename T> |
| void testInvalidWritableParam(T* invalidParam) { |
| // Get the current parameter info |
| T preParam; |
| std::vector<C2Param*> stackParams{&preParam}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams, {}, C2_DONT_BLOCK, nullptr)); |
| |
| // Config invalid value. The failure is expected |
| std::vector<C2Param*> params{invalidParam}; |
| std::vector<std::unique_ptr<C2SettingResult>> failures; |
| ASSERT_EQ(C2_BAD_VALUE, mIntf->config_vb(params, C2_DONT_BLOCK, &failures)); |
| EXPECT_EQ(1u, failures.size()); |
| |
| // The param must not change after config failed |
| T param; |
| std::vector<C2Param*> stackParams2{¶m}; |
| ASSERT_EQ(C2_OK, mIntf->query_vb(stackParams2, {}, C2_DONT_BLOCK, nullptr)); |
| EXPECT_EQ(preParam, param); |
| |
| // Check also like param on heap |
| std::vector<std::unique_ptr<C2Param>> heapParams; |
| ASSERT_EQ(C2_OK, mIntf->query_vb({}, {invalidParam->index()}, C2_DONT_BLOCK, &heapParams)); |
| ASSERT_EQ(1u, heapParams.size()); |
| EXPECT_EQ(preParam, *heapParams[0]); |
| } |
| |
| bool isUnderflowSubstract(int32_t a, int32_t b) { |
| return a < 0 && b > a - std::numeric_limits<int32_t>::min(); |
| } |
| |
| bool isOverflowAdd(int32_t a, int32_t b) { |
| return a > 0 && b > std::numeric_limits<int32_t>::max() - a; |
| } |
| |
| template <typename T> |
| void testWritableVideoSizeParam(int32_t widthMin, int32_t widthMax, int32_t widthStep, |
| int32_t heightMin, int32_t heightMax, int32_t heightStep) { |
| // Test supported values of video size |
| T valid; |
| for (int32_t h = heightMin; h <= heightMax; h += heightStep) { |
| for (int32_t w = widthMin; w <= widthMax; w += widthStep) { |
| valid.width = w; |
| valid.height = h; |
| { |
| SCOPED_TRACE("testWritableParam"); |
| testWritableParam(&valid); |
| if (HasFailure()) { |
| printf("Failed while config width = %d, height = %d\n", valid.width, |
| valid.height); |
| } |
| if (HasFatalFailure()) return; |
| } |
| } |
| } |
| |
| // TODO: validate possible values in C2InterfaceHelper is not implemented yet. |
| //// Test invalid values video size |
| //T invalid; |
| //// Width or height is smaller than min values |
| //if (!isUnderflowSubstract(widthMin, widthStep)) { |
| // invalid.width = widthMin - widthStep; |
| // invalid.height = heightMin; |
| // testInvalidWritableParam(&invalid); |
| //} |
| //if (!isUnderflowSubstract(heightMin, heightStep)) { |
| // invalid.width = widthMin; |
| // invalid.height = heightMin - heightStep; |
| // testInvalidWritableParam(&invalid); |
| //} |
| |
| //// Width or height is bigger than max values |
| //if (!isOverflowAdd(widthMax, widthStep)) { |
| // invalid.width = widthMax + widthStep; |
| // invalid.height = heightMax; |
| // testInvalidWritableParam(&invalid); |
| //} |
| //if (!isOverflowAdd(heightMax, heightStep)) { |
| // invalid.width = widthMax; |
| // invalid.height = heightMax + heightStep; |
| // testInvalidWritableParam(&invalid); |
| //} |
| |
| //// Invalid width/height within the range |
| //if (widthStep != 1) { |
| // invalid.width = widthMin + 1; |
| // invalid.height = heightMin; |
| // testInvalidWritableParam(&invalid); |
| //} |
| //if (heightStep != 1) { |
| // invalid.width = widthMin; |
| // invalid.height = heightMin + 1; |
| // testInvalidWritableParam(&invalid); |
| //} |
| } |
| |
| template <typename T> |
| void testWritableProfileLevelParam() { |
| T info; |
| |
| std::vector<C2FieldSupportedValuesQuery> profileC2FSV = { |
| {C2ParamField(&info, &C2StreamProfileLevelInfo::profile), |
| C2FieldSupportedValuesQuery::CURRENT}, |
| }; |
| ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(profileC2FSV, C2_DONT_BLOCK)); |
| ASSERT_EQ(1u, profileC2FSV.size()); |
| ASSERT_EQ(C2_OK, profileC2FSV[0].status); |
| ASSERT_EQ(C2FieldSupportedValues::VALUES, profileC2FSV[0].values.type); |
| auto& profileFSVValues = profileC2FSV[0].values.values; |
| |
| std::vector<C2FieldSupportedValuesQuery> levelC2FSV = { |
| {C2ParamField(&info, &C2StreamProfileLevelInfo::level), |
| C2FieldSupportedValuesQuery::CURRENT}, |
| }; |
| ASSERT_EQ(C2_OK, mIntf->querySupportedValues_vb(levelC2FSV, C2_DONT_BLOCK)); |
| ASSERT_EQ(1u, levelC2FSV.size()); |
| ASSERT_EQ(C2_OK, levelC2FSV[0].status); |
| ASSERT_EQ(C2FieldSupportedValues::VALUES, levelC2FSV[0].values.type); |
| auto& levelFSVValues = levelC2FSV[0].values.values; |
| |
| for (const auto& profile : profileFSVValues) { |
| for (const auto& level : levelFSVValues) { |
| info.profile = static_cast<C2Config::profile_t>(profile.u32); |
| info.level = static_cast<C2Config::level_t>(level.u32); |
| { |
| SCOPED_TRACE("testWritableParam"); |
| testWritableParam(&info); |
| if (HasFailure()) { |
| printf("Failed while config profile = 0x%x, level = 0x%x\n", info.profile, |
| info.level); |
| } |
| if (HasFatalFailure()) return; |
| } |
| } |
| } |
| // TODO: Add invalid value test after validate possible values in C2InterfaceHelper is |
| // implemented. |
| } |
| |
| protected: |
| std::shared_ptr<C2ComponentInterface> mIntf; |
| std::shared_ptr<C2ReflectorHelper> mReflector; |
| }; |
| |
| } // namespace android |
| |
| #endif // ANDROID_C2_COMPONENT_INTERFACE_TEST_H |